summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-07-20 14:56:40 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-07-20 14:56:40 +0000
commite308faf24f68e262d92d294a01ddca7a17e76762 (patch)
tree22c47cb315811834861f013067878ff664e95abd /fs
parent30c6397ce63178fcb3e7963ac247f0a03132aca9 (diff)
Sync with Linux 2.1.46.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in20
-rw-r--r--fs/affs/Changes20
-rw-r--r--fs/affs/amigaffs.c21
-rw-r--r--fs/affs/file.c80
-rw-r--r--fs/affs/inode.c10
-rw-r--r--fs/affs/namei.c10
-rw-r--r--fs/attr.c2
-rw-r--r--fs/autofs/autofs_i.h11
-rw-r--r--fs/autofs/dir.c24
-rw-r--r--fs/autofs/dirhash.c28
-rw-r--r--fs/autofs/init.c2
-rw-r--r--fs/autofs/inode.c251
-rw-r--r--fs/autofs/root.c270
-rw-r--r--fs/autofs/symlink.c14
-rw-r--r--fs/autofs/waitq.c20
-rw-r--r--fs/binfmt_aout.c45
-rw-r--r--fs/binfmt_elf.c116
-rw-r--r--fs/binfmt_em86.c26
-rw-r--r--fs/binfmt_java.c40
-rw-r--r--fs/binfmt_misc.c38
-rw-r--r--fs/binfmt_script.c21
-rw-r--r--fs/buffer.c89
-rw-r--r--fs/dcache.c1168
-rw-r--r--fs/devices.c4
-rw-r--r--fs/dquot.c87
-rw-r--r--fs/exec.c108
-rw-r--r--fs/ext2/balloc.c6
-rw-r--r--fs/ext2/dir.c6
-rw-r--r--fs/ext2/file.c5
-rw-r--r--fs/ext2/ialloc.c56
-rw-r--r--fs/ext2/inode.c21
-rw-r--r--fs/ext2/ioctl.c4
-rw-r--r--fs/ext2/namei.c416
-rw-r--r--fs/ext2/super.c10
-rw-r--r--fs/ext2/symlink.c37
-rw-r--r--fs/ext2/truncate.c209
-rw-r--r--fs/fat/cache.c2
-rw-r--r--fs/fat/file.c8
-rw-r--r--fs/fat/inode.c13
-rw-r--r--fs/fat/misc.c29
-rw-r--r--fs/fat/mmap.c7
-rw-r--r--fs/fcntl.c55
-rw-r--r--fs/fifo.c1
-rw-r--r--fs/file_table.c42
-rw-r--r--fs/filesystems.c5
-rw-r--r--fs/inode.c992
-rw-r--r--fs/ioctl.c21
-rw-r--r--fs/isofs/dir.c19
-rw-r--r--fs/isofs/file.c1
-rw-r--r--fs/isofs/inode.c15
-rw-r--r--fs/isofs/namei.c82
-rw-r--r--fs/lockd/clntlock.c2
-rw-r--r--fs/lockd/clntproc.c2
-rw-r--r--fs/lockd/svclock.c16
-rw-r--r--fs/locks.c68
-rw-r--r--fs/minix/bitmap.c8
-rw-r--r--fs/minix/dir.c1
-rw-r--r--fs/minix/file.c3
-rw-r--r--fs/minix/inode.c39
-rw-r--r--fs/minix/namei.c293
-rw-r--r--fs/minix/symlink.c18
-rw-r--r--fs/minix/truncate.c14
-rw-r--r--fs/msdos/namei.c31
-rw-r--r--fs/namei.c1615
-rw-r--r--fs/ncpfs/inode.c2
-rw-r--r--fs/ncpfs/mmap.c4
-rw-r--r--fs/nfs/dir.c546
-rw-r--r--fs/nfs/file.c7
-rw-r--r--fs/nfs/inode.c31
-rw-r--r--fs/nfs/nfsroot.c15
-rw-r--r--fs/nfs/read.c2
-rw-r--r--fs/nfs/symlink.c36
-rw-r--r--fs/nfs/write.c5
-rw-r--r--fs/nfsd/export.c2
-rw-r--r--fs/nfsd/vfs.c34
-rw-r--r--fs/open.c425
-rw-r--r--fs/pipe.c73
-rw-r--r--fs/proc/Makefile2
-rw-r--r--fs/proc/arbitrary.c58
-rw-r--r--fs/proc/array.c15
-rw-r--r--fs/proc/base.c1
-rw-r--r--fs/proc/fd.c49
-rw-r--r--fs/proc/generic.c11
-rw-r--r--fs/proc/inode.c23
-rw-r--r--fs/proc/kmsg.c1
-rw-r--r--fs/proc/link.c115
-rw-r--r--fs/proc/mem.c1
-rw-r--r--fs/proc/net.c1
-rw-r--r--fs/proc/omirr.c2
-rw-r--r--fs/proc/openpromfs.c115
-rw-r--r--fs/proc/procfs_syms.c2
-rw-r--r--fs/proc/root.c149
-rw-r--r--fs/proc/scsi.c1
-rw-r--r--fs/read_write.c68
-rw-r--r--fs/readdir.c232
-rw-r--r--fs/romfs/inode.c2
-rw-r--r--fs/smbfs/inode.c2
-rw-r--r--fs/smbfs/mmap.c4
-rw-r--r--fs/stat.c155
-rw-r--r--fs/super.c382
-rw-r--r--fs/sysv/dir.c1
-rw-r--r--fs/sysv/file.c7
-rw-r--r--fs/sysv/ialloc.c11
-rw-r--r--fs/sysv/inode.c15
-rw-r--r--fs/sysv/namei.c81
-rw-r--r--fs/sysv/symlink.c18
-rw-r--r--fs/sysv/truncate.c12
-rw-r--r--fs/ufs/ufs_file.c3
-rw-r--r--fs/ufs/ufs_inode.c5
-rw-r--r--fs/ufs/ufs_namei.c6
-rw-r--r--fs/ufs/ufs_super.c4
-rw-r--r--fs/vfat/namei.c20
112 files changed, 3886 insertions, 5567 deletions
diff --git a/fs/Config.in b/fs/Config.in
index a9f922d8a..cfc601630 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -5,26 +5,6 @@ mainmenu_option next_comment
comment 'Filesystems'
bool 'Quota support' CONFIG_QUOTA
-bool 'Preload dcache entries in readdir() [ALPHA, currently dangerous!]' CONFIG_DCACHE_PRELOAD
-bool 'Include support for omirr online mirror' CONFIG_OMIRR
-bool 'Translate filename suffixes' CONFIG_TRANS_NAMES
-if [ "$CONFIG_TRANS_NAMES" = "y" ]; then
- bool ' Restrict translation to specific gid' CONFIG_TRANS_RESTRICT
- if [ "$CONFIG_TRANS_RESTRICT" = "y" ]; then
- int ' Enter gid to compile in' CONFIG_TRANS_GID 4
- fi
- bool ' Translate nodename' CONFIG_TR_NODENAME
- bool ' Translate compiled-in kernelname' CONFIG_TR_KERNNAME
- if [ "$CONFIG_TR_KERNNAME" = "y" ]; then
- string ' Enter kernelname string to compile in' CONFIG_KERNNAME banana
- fi
- bool ' Translate compiled-in kerneltype' CONFIG_TR_KERNTYPE
- if [ "$CONFIG_TR_KERNTYPE" = "y" ]; then
- string ' Enter kerneltype string to compile in' CONFIG_KERNTYPE default
- fi
- bool ' Translate machine type' CONFIG_TR_MACHINE
- bool ' Translate sysname' CONFIG_TR_SYSNAME
-fi
tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
diff --git a/fs/affs/Changes b/fs/affs/Changes
index a65dc326a..b19c24ae6 100644
--- a/fs/affs/Changes
+++ b/fs/affs/Changes
@@ -13,11 +13,25 @@ Known bugs:
reads basically work (but all files are of size 0).
Alas, I've got no alpha to debug. :-(
- If an affs mounted filesystem is exported via
- nfs, it cannot be written to. No networking to
- test that, either. :-(
+ nfs, it cannot be written to.
+ As soon as I have my network up and running, I'll
+ try to fix this.
+- The partition checker (drivers/block/genhd.c)
+ doesn't work with devices which have 256 byte
+ blocks (some very old SCSI drives).
Please direct bug reports to: hjw@zvw.de
+Version 3.5
+-----------
+
+- Extension block caches are now allocated on
+ demand instead of when a file is opened, as
+ files can be read and written without opening
+ them (e. g. the loopback device does this).
+
+- Removed an unused function.
+
Version 3.4
-----------
@@ -80,7 +94,7 @@ Version 3.0
interface in Linux 1.3.
- Write support.
- Support for hard and symbolic links.
-- Lots of things I remeber even less ...
+- Lots of things I remember even less ...
Version 2.0
-----------
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 4afd66e49..7ddb54a62 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -26,27 +26,6 @@ static char ErrorBuffer[256];
*
*/
-/* Find the next used hash entry at or after *HASH_POS in a directory's hash
- table. *HASH_POS is assigned that entry's number. DIR_DATA points to
- the directory header block in memory. If there are no more entries,
- 0 is returned. Otherwise, the key number in the next used hash slot
- is returned. */
-
-static int
-affs_find_next_hash_entry(int hsize, void *dir_data, int *hash_pos)
-{
- struct dir_front *dir_front = dir_data;
- int i;
-
- for (i = *hash_pos; i < hsize; i++)
- if (dir_front->hashtable[i] != 0)
- break;
- if (i >= hsize)
- return 0;
- *hash_pos = i;
- return htonl(dir_front->hashtable[i]);
-}
-
/* Set *NAME to point to the file name in a file header block in memory
pointed to by FH_DATA. The length of the name is returned. */
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 46b10bcb1..7777e4763 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -43,8 +43,8 @@ static long affs_file_write(struct inode *inode, struct file *filp, const char *
unsigned long count);
static long affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf,
unsigned long count);
-static int affs_open_file(struct inode *inode, struct file *filp);
static int affs_release_file(struct inode *inode, struct file *filp);
+static int alloc_ext_cache(struct inode *inode);
static struct file_operations affs_file_operations = {
NULL, /* lseek - default */
@@ -54,7 +54,7 @@ static struct file_operations affs_file_operations = {
NULL, /* poll - default */
NULL, /* ioctl - default */
generic_file_mmap, /* mmap */
- affs_open_file, /* special open is needed */
+ NULL, /* no special open */
affs_release_file, /* release */
file_fsync /* brute force, but works */
};
@@ -87,7 +87,7 @@ static struct file_operations affs_file_operations_ofs = {
NULL, /* poll - default */
NULL, /* ioctl - default */
NULL, /* mmap */
- affs_open_file, /* special open is needed */
+ NULL, /* no special open */
affs_release_file, /* release */
file_fsync /* brute force, but works */
};
@@ -248,9 +248,9 @@ affs_bmap(struct inode *inode, int block)
return 0;
}
if (!inode->u.affs_i.i_ec) {
- affs_error(inode->i_sb,"bmap","No extension cache for open file (inode=%lu)",
- inode->i_ino);
- return 0;
+ if (alloc_ext_cache(inode)) {
+ return 0;
+ }
}
/* Try to find the requested key in the cache.
@@ -582,6 +582,12 @@ affs_file_write(struct inode *inode, struct file *filp, const char *buf, unsigne
iput(inode);
return -EINVAL;
}
+ if (!inode->u.affs_i.i_ec) {
+ if (alloc_ext_cache(inode)) {
+ iput(inode);
+ return -ENOMEM;
+ }
+ }
if (filp->f_flags & O_APPEND) {
pos = inode->i_size;
} else
@@ -861,40 +867,6 @@ affs_truncate(struct inode *inode)
}
static int
-affs_open_file(struct inode *inode, struct file *filp)
-{
- int error;
- u32 key;
- int i;
-
- pr_debug("AFFS: open_file(ino=%lu)\n",inode->i_ino);
-
- error = 0;
- inode->u.affs_i.i_cache_users++;
- lock_super(inode->i_sb);
- if (!inode->u.affs_i.i_ec) {
- inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
- if (!inode->u.affs_i.i_ec) {
- affs_error(inode->i_sb,"open_file","Cache allocation failed");
- error = ENOMEM;
- } else {
- /* We only have to initialize non-zero values.
- * get_free_page() zeroed the page already.
- */
- key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
- inode->u.affs_i.i_ec->ec[0] = key;
- for (i = 0; i < 4; i++) {
- inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
- inode->u.affs_i.i_ec->kc[i].kc_last = -1;
- }
- }
- }
- unlock_super(inode->i_sb);
-
- return error;
-}
-
-static int
affs_release_file(struct inode *inode, struct file *filp)
{
struct affs_zone *zone;
@@ -916,13 +888,35 @@ affs_release_file(struct inode *inode, struct file *filp)
unlock_super(inode->i_sb);
}
}
+ return 0;
+}
+
+static int
+alloc_ext_cache(struct inode *inode)
+{
+ s32 key;
+ int i;
+
lock_super(inode->i_sb);
- if (--inode->u.affs_i.i_cache_users == 0) {
+ if (!inode->u.affs_i.i_ec) {
+ inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
if (inode->u.affs_i.i_ec) {
- free_page((unsigned long)inode->u.affs_i.i_ec);
- inode->u.affs_i.i_ec = NULL;
+ /* We only have to initialize non-zero values.
+ * get_free_page() zeroed the page already.
+ */
+ key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+ inode->u.affs_i.i_ec->ec[0] = key;
+ for (i = 0; i < 4; i++) {
+ inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
+ inode->u.affs_i.i_ec->kc[i].kc_last = -1;
+ }
}
}
unlock_super(inode->i_sb);
+
+ if (!inode->u.affs_i.i_ec) {
+ affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed");
+ return -ENOMEM;
+ }
return 0;
}
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 2805f1ccf..a1e380cce 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -691,7 +691,6 @@ affs_read_inode(struct inode *inode)
inode->u.affs_i.i_pa_next = 0;
inode->u.affs_i.i_pa_last = 0;
inode->u.affs_i.i_ec = NULL;
- inode->u.affs_i.i_cache_users = 0;
inode->u.affs_i.i_lastblock = -1;
inode->i_nlink = 1;
inode->i_mode = 0;
@@ -870,6 +869,12 @@ static void
affs_put_inode(struct inode *inode)
{
pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
+ lock_super(inode->i_sb);
+ if (inode->u.affs_i.i_ec) {
+ free_page((unsigned long)inode->u.affs_i.i_ec);
+ inode->u.affs_i.i_ec = NULL;
+ }
+ unlock_super(inode->i_sb);
if (inode->i_nlink) {
return;
}
@@ -899,7 +904,7 @@ affs_new_inode(const struct inode *dir)
return NULL;
}
- atomic_set(&inode->i_count, 1);
+ inode->i_count = 1;
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
@@ -921,7 +926,6 @@ affs_new_inode(const struct inode *dir)
inode->u.affs_i.i_pa_next = 0;
inode->u.affs_i.i_pa_last = 0;
inode->u.affs_i.i_ec = NULL;
- inode->u.affs_i.i_cache_users = 0;
inode->u.affs_i.i_lastblock = -1;
insert_inode_hash(inode);
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 5ea649425..ce04df073 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -343,7 +343,7 @@ affs_rmdir(struct inode *dir, const char *name, int len)
retval = -ENOTEMPTY;
goto rmdir_done;
}
- if (atomic_read(&inode->i_count) > 1) {
+ if (inode->i_count > 1) {
retval = -EBUSY;
goto rmdir_done;
}
@@ -512,7 +512,7 @@ subdir(struct inode *new_inode, struct inode *old_inode)
int ino;
int result;
- atomic_inc(&new_inode->i_count);
+ new_inode->i_count++;
result = 0;
for (;;) {
if (new_inode == old_inode) {
@@ -566,12 +566,12 @@ start_up:
old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
if (!old_bh)
goto end_rename;
- old_inode = __iget(old_dir->i_sb,old_ino,0);
+ old_inode = iget(old_dir->i_sb,old_ino);
if (!old_inode)
goto end_rename;
new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
if (new_bh) {
- new_inode = __iget(new_dir->i_sb,new_ino,0);
+ new_inode = iget(new_dir->i_sb,new_ino);
if (!new_inode) { /* What does this mean? */
affs_brelse(new_bh);
new_bh = NULL;
@@ -592,7 +592,7 @@ start_up:
if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
goto end_rename;
retval = -EBUSY;
- if (atomic_read(&new_inode->i_count) > 1)
+ if (new_inode->i_count > 1)
goto end_rename;
}
if (S_ISDIR(old_inode->i_mode)) {
diff --git a/fs/attr.c b/fs/attr.c
index be824dd4a..7a6b9f814 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -74,7 +74,7 @@ void inode_setattr(struct inode * inode, struct iattr * attr)
if (!fsuser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
}
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
}
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index cc38577aa..f2bb6c339 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -69,10 +69,8 @@ static inline int copy_from_user(void *dst, void *src, unsigned long len)
#define AUTOFS_HASH_SIZE 67
-typedef u32 autofs_hash_t; /* Type returned by autofs_hash() */
-
struct autofs_dir_ent {
- autofs_hash_t hash;
+ int hash;
struct autofs_dir_ent *next;
struct autofs_dir_ent **back;
char *name;
@@ -94,7 +92,7 @@ struct autofs_wait_queue {
struct wait_queue *queue;
struct autofs_wait_queue *next;
/* We use the following to see what we are waiting for */
- autofs_hash_t hash;
+ int hash;
int len;
char *name;
/* This is for status reporting upon return */
@@ -151,9 +149,8 @@ void autofs_check_waitlist_integrity(struct autofs_sb_info *,char *);
/* Hash operations */
-autofs_hash_t autofs_hash(const char *,int);
void autofs_initialize_hash(struct autofs_dirhash *);
-struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,autofs_hash_t,const char *,int);
+struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,struct qstr *);
void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
void autofs_hash_delete(struct autofs_dir_ent *);
struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *);
@@ -176,7 +173,7 @@ struct super_block *autofs_read_super(struct super_block *, void *,int);
/* Queue management functions */
-int autofs_wait(struct autofs_sb_info *,autofs_hash_t,const char *,int);
+int autofs_wait(struct autofs_sb_info *,struct qstr *);
int autofs_wait_release(struct autofs_sb_info *,unsigned long,int);
void autofs_catatonic_mode(struct autofs_sb_info *);
diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c
index 0f529c900..61900c481 100644
--- a/fs/autofs/dir.c
+++ b/fs/autofs/dir.c
@@ -34,25 +34,13 @@ static int autofs_dir_readdir(struct inode *inode, struct file *filp,
return 1;
}
-static int autofs_dir_lookup(struct inode *dir, const char *name, int len,
- struct inode **result)
+/*
+ * 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)
{
- *result = dir;
- if (!len)
- return 0;
- if (name[0] == '.') {
- if (len == 1)
- return 0;
- if (name[1] == '.' && len == 2) {
- /* Return the root directory */
- *result = iget(dir->i_sb,AUTOFS_ROOT_INO);
- iput(dir);
- return 0;
- }
- }
- *result = NULL;
- iput(dir);
- return -ENOENT; /* No other entries */
+ d_add(dentry, NULL);
+ return 0;
}
static struct file_operations autofs_dir_operations = {
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
index 90c18695a..60a3c6933 100644
--- a/fs/autofs/dirhash.c
+++ b/fs/autofs/dirhash.c
@@ -48,35 +48,23 @@ struct autofs_dir_ent *autofs_expire(struct autofs_dirhash *dh,
return (jiffies - ent->last_usage >= timeout) ? ent : NULL;
}
-/* Adapted from the Dragon Book, page 436 */
-/* This particular hashing algorithm requires autofs_hash_t == u32 */
-autofs_hash_t autofs_hash(const char *name, int len)
-{
- autofs_hash_t h = 0;
- while ( len-- ) {
- h = (h << 4) + (unsigned char) (*name++);
- h ^= ((h & 0xf0000000) >> 24);
- }
- return h;
-}
-
void autofs_initialize_hash(struct autofs_dirhash *dh) {
memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *));
dh->expiry_head.exp_next = dh->expiry_head.exp_prev =
&dh->expiry_head;
}
-struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, autofs_hash_t hash, const char *name, int len)
+struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, struct qstr *name)
{
struct autofs_dir_ent *dhn;
- DPRINTK(("autofs_hash_lookup: hash = 0x%08x, name = ", hash));
- autofs_say(name,len);
+ DPRINTK(("autofs_hash_lookup: hash = 0x%08x, name = ", name->hash));
+ autofs_say(name->name,name->len);
- for ( dhn = dh->h[hash % AUTOFS_HASH_SIZE] ; dhn ; dhn = dhn->next ) {
- if ( hash == dhn->hash &&
- len == dhn->len &&
- !memcmp(name, dhn->name, len) )
+ for ( dhn = dh->h[(unsigned) name->hash % AUTOFS_HASH_SIZE] ; dhn ; dhn = dhn->next ) {
+ if ( name->hash == dhn->hash &&
+ name->len == dhn->len &&
+ !memcmp(name->name, dhn->name, name->len) )
break;
}
@@ -92,7 +80,7 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
autofs_init_usage(dh,ent);
- dhnp = &dh->h[ent->hash % AUTOFS_HASH_SIZE];
+ dhnp = &dh->h[(unsigned) ent->hash % AUTOFS_HASH_SIZE];
ent->next = *dhnp;
ent->back = dhnp;
*dhnp = ent;
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index 4dbb76c85..ed4401ce5 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -21,7 +21,7 @@
static struct file_system_type autofs_fs_type = {
"autofs",
- FS_NO_DCACHE,
+ 0 /* FS_NO_DCACHE doesn't work correctly */,
autofs_read_super,
NULL
};
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index 20ca0907a..870ff120d 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -19,11 +19,17 @@
#define __NO_VERSION__
#include <linux/module.h>
+/*
+ * Dummy functions - do we ever actually want to do
+ * something here?
+ */
static void autofs_put_inode(struct inode *inode)
{
- if (inode->i_nlink)
- return;
- inode->i_size = 0;
+}
+
+static void autofs_delete_inode(struct inode *inode)
+{
+ inode->i_size = 0;
}
static void autofs_put_super(struct super_block *sb)
@@ -35,16 +41,16 @@ static void autofs_put_super(struct super_block *sb)
if ( !sbi->catatonic )
autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */
- lock_super(sb);
+ lock_super(sb);
autofs_hash_nuke(&sbi->dirhash);
for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) {
if ( test_bit(n, sbi->symlink_bitmap) )
kfree(sbi->symlink[n].data);
}
- sb->s_dev = 0;
+ sb->s_dev = 0;
kfree(sb->u.generic_sbp);
- unlock_super(sb);
+ unlock_super(sb);
DPRINTK(("autofs: shutting down\n"));
@@ -53,95 +59,96 @@ static void autofs_put_super(struct super_block *sb)
#endif
}
-static void autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
static void autofs_read_inode(struct inode *inode);
static void autofs_write_inode(struct inode *inode);
static struct super_operations autofs_sops = {
- autofs_read_inode,
- NULL,
- autofs_write_inode,
- autofs_put_inode,
- autofs_put_super,
- NULL,
- autofs_statfs,
- NULL
+ autofs_read_inode,
+ autofs_write_inode,
+ autofs_put_inode,
+ autofs_delete_inode,
+ NULL, /* notify_change */
+ autofs_put_super,
+ NULL, /* write_super */
+ autofs_statfs,
+ NULL
};
static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto)
{
- char *this_char, *value;
-
- *uid = current->uid;
- *gid = current->gid;
+ char *this_char, *value;
+
+ *uid = current->uid;
+ *gid = current->gid;
*pgrp = current->pgrp;
*minproto = *maxproto = AUTOFS_PROTO_VERSION;
- *pipefd = -1;
+ *pipefd = -1;
- if ( !options ) return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
- if ((value = strchr(this_char,'=')) != NULL)
- *value++ = 0;
- if (!strcmp(this_char,"fd")) {
- if (!value || !*value)
- return 1;
- *pipefd = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- }
- else if (!strcmp(this_char,"uid")) {
- if (!value || !*value)
- return 1;
- *uid = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- }
- else if (!strcmp(this_char,"gid")) {
- if (!value || !*value)
- return 1;
- *gid = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- }
- else if (!strcmp(this_char,"pgrp")) {
- if (!value || !*value)
- return 1;
- *pgrp = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- }
- else if (!strcmp(this_char,"minproto")) {
- if (!value || !*value)
- return 1;
- *minproto = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- }
- else if (!strcmp(this_char,"maxproto")) {
- if (!value || !*value)
- return 1;
- *maxproto = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- }
- else break;
- }
- return (*pipefd < 0);
+ if ( !options ) return 1;
+ for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ if ((value = strchr(this_char,'=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(this_char,"fd")) {
+ if (!value || !*value)
+ return 1;
+ *pipefd = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"uid")) {
+ if (!value || !*value)
+ return 1;
+ *uid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"gid")) {
+ if (!value || !*value)
+ return 1;
+ *gid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"pgrp")) {
+ if (!value || !*value)
+ return 1;
+ *pgrp = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"minproto")) {
+ if (!value || !*value)
+ return 1;
+ *minproto = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"maxproto")) {
+ if (!value || !*value)
+ return 1;
+ *maxproto = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else break;
+ }
+ return (*pipefd < 0);
}
struct super_block *autofs_read_super(struct super_block *s, void *data,
- int silent)
+ int silent)
{
- int pipefd;
+ int pipefd;
struct autofs_sb_info *sbi;
int minproto, maxproto;
MOD_INC_USE_COUNT;
- lock_super(s);
- sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
+ lock_super(s);
+ sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
if ( !sbi ) {
s->s_dev = 0;
MOD_DEC_USE_COUNT;
@@ -158,30 +165,31 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
sbi->queues = NULL;
memset(sbi->symlink_bitmap, 0, sizeof(u32)*AUTOFS_SYMLINK_BITMAP_LEN);
sbi->next_dir_ino = AUTOFS_FIRST_DIR_INO;
- s->s_blocksize = 1024;
- s->s_blocksize_bits = 10;
- s->s_magic = AUTOFS_SUPER_MAGIC;
- s->s_op = &autofs_sops;
- unlock_super(s);
- if (!(s->s_mounted = iget(s, AUTOFS_ROOT_INO))) {
- s->s_dev = 0;
+ s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
+ s->s_magic = AUTOFS_SUPER_MAGIC;
+ s->s_op = &autofs_sops;
+ unlock_super(s);
+ s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
+ if (!s->s_root) {
+ s->s_dev = 0;
kfree(sbi);
- printk("autofs: get root inode failed\n");
+ printk("autofs: get root inode failed\n");
MOD_DEC_USE_COUNT;
- return NULL;
- }
+ return NULL;
+ }
- if ( parse_options(data,&pipefd,&s->s_mounted->i_uid,&s->s_mounted->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
- iput(s->s_mounted);
- s->s_dev = 0;
+ if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+ dput(s->s_root);
+ s->s_dev = 0;
kfree(sbi);
- printk("autofs: called with bogus options\n");
+ printk("autofs: called with bogus options\n");
MOD_DEC_USE_COUNT;
- return NULL;
- }
+ return NULL;
+ }
if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
- iput(s->s_mounted);
+ dput(s->s_root);
s->s_dev = 0;
kfree(sbi);
printk("autofs: kernel does not match daemon version\n");
@@ -193,60 +201,60 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
sbi->pipe = fget(pipefd);
if ( !sbi->pipe || !sbi->pipe->f_op || !sbi->pipe->f_op->write ) {
if ( sbi->pipe ) {
- fput(sbi->pipe, sbi->pipe->f_inode);
+ fput(sbi->pipe);
printk("autofs: pipe file descriptor does not contain proper ops\n");
} else {
printk("autofs: could not open pipe file descriptor\n");
}
- iput(s->s_mounted);
+ dput(s->s_root);
s->s_dev = 0;
kfree(sbi);
MOD_DEC_USE_COUNT;
return NULL;
}
- return s;
+ return s;
}
-static void autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
- struct statfs tmp;
+ struct statfs tmp;
- tmp.f_type = AUTOFS_SUPER_MAGIC;
- tmp.f_bsize = 1024;
- tmp.f_blocks = 0;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- copy_to_user(buf, &tmp, bufsiz);
+ tmp.f_type = AUTOFS_SUPER_MAGIC;
+ tmp.f_bsize = 1024;
+ tmp.f_blocks = 0;
+ tmp.f_bfree = 0;
+ tmp.f_bavail = 0;
+ tmp.f_files = 0;
+ tmp.f_ffree = 0;
+ tmp.f_namelen = NAME_MAX;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
static void autofs_read_inode(struct inode *inode)
{
- ino_t ino = inode->i_ino;
+ ino_t ino = inode->i_ino;
unsigned int n;
- struct autofs_sb_info *sbi =
+ struct autofs_sb_info *sbi =
(struct autofs_sb_info *) inode->i_sb->u.generic_sbp;
- inode->i_op = NULL;
- inode->i_mode = 0;
- inode->i_nlink = 2;
- inode->i_size = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_blocks = 0;
- inode->i_blksize = 1024;
+ inode->i_op = NULL;
+ inode->i_mode = 0;
+ inode->i_nlink = 2;
+ inode->i_size = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = 0;
+ inode->i_blksize = 1024;
- if ( ino == AUTOFS_ROOT_INO ) {
- inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
- inode->i_op = &autofs_root_inode_operations;
+ if ( ino == AUTOFS_ROOT_INO ) {
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
+ inode->i_op = &autofs_root_inode_operations;
inode->i_uid = inode->i_gid = 0; /* Changed in read_super */
- return;
- }
+ return;
+ }
+
+ inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
+ inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
- inode->i_uid = inode->i_sb->s_mounted->i_uid;
- inode->i_gid = inode->i_sb->s_mounted->i_gid;
-
if ( ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO ) {
/* Symlink inode - should be in symlink list */
struct autofs_symlink *sl;
@@ -273,5 +281,4 @@ static void autofs_read_inode(struct inode *inode)
static void autofs_write_inode(struct inode *inode)
{
- inode->i_dirt = 0;
}
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index a615ede29..4ecc6520e 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -16,11 +16,11 @@
#include "autofs_i.h"
static int autofs_root_readdir(struct inode *,struct file *,void *,filldir_t);
-static int autofs_root_lookup(struct inode *,const char *,int,struct inode **);
-static int autofs_root_symlink(struct inode *,const char *,int,const char *);
-static int autofs_root_unlink(struct inode *,const char *,int);
-static int autofs_root_rmdir(struct inode *,const char *,int);
-static int autofs_root_mkdir(struct inode *,const char *,int,int);
+static int 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 *);
+static int autofs_root_mkdir(struct inode *,struct dentry *,int);
static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
static struct file_operations autofs_root_operations = {
@@ -48,6 +48,7 @@ struct inode_operations autofs_root_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -92,167 +93,189 @@ static int autofs_root_readdir(struct inode *inode, struct file *filp,
return 0;
}
-static int autofs_root_lookup(struct inode *dir, const char *name, int len,
- struct inode **result)
+static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, struct autofs_sb_info *sbi)
{
- struct autofs_sb_info *sbi;
+ struct inode * inode;
struct autofs_dir_ent *ent;
- struct inode *res;
- autofs_hash_t hash;
- int status, oz_mode;
+
+ while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
+ int status = autofs_wait(sbi, &dentry->d_name);
- DPRINTK(("autofs_root_lookup: name = "));
- autofs_say(name,len);
+ /* Turn this into a real negative dentry? */
+ if (status == -ENOENT) {
+ dentry->d_flags = 0;
+ return 0;
+ }
+ if (status)
+ return status;
+ }
- *result = NULL;
- if (!dir)
- return -ENOENT;
- if (!S_ISDIR(dir->i_mode)) {
- iput(dir);
- return -ENOTDIR;
+ if (!dentry->d_inode) {
+ inode = iget(sb, ent->ino);
+ if (!inode)
+ return -EACCES;
+
+ dentry->d_inode = inode;
}
- /* Handle special cases: . and ..; since this is a root directory,
- they both point to the inode itself */
- *result = dir;
- if (!len)
- return 0;
- if (name[0] == '.') {
- if (len == 1)
- return 0;
- if (name[1] == '.' && len == 2)
- return 0;
+ if (S_ISDIR(dentry->d_inode->i_mode)) {
+ while (dentry == dentry->d_mounts)
+ schedule();
}
+ dentry->d_flags = 0;
+ return 0;
+}
+
+
+/*
+ * Revalidate is called on every cache lookup. Some of those
+ * cache lookups may actually happen while the dentry is not
+ * yet completely filled in, and revalidate has to delay such
+ * lookups..
+ */
+static struct dentry * autofs_revalidate(struct dentry * dentry)
+{
+ struct autofs_sb_info *sbi;
+ struct inode * dir = dentry->d_parent->d_inode;
- *result = res = NULL;
sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
- hash = autofs_hash(name,len);
+ /* Incomplete dentry? */
+ if (dentry->d_flags) {
+ if (autofs_oz_mode(sbi))
+ return dentry;
- oz_mode = autofs_oz_mode(sbi);
- DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n", current->pid, current->pgrp, sbi->catatonic, oz_mode));
+ try_to_fill_dentry(dentry, dir->i_sb, sbi);
+ return dentry;
+ }
- do {
- while ( !(ent = autofs_hash_lookup(&sbi->dirhash,hash,name,len)) ) {
- DPRINTK(("lookup failed, pid = %u, pgrp = %u\n", current->pid, current->pgrp));
-
- if ( oz_mode ) {
- iput(dir);
- return -ENOENT;
- } else {
- status = autofs_wait(sbi,hash,name,len);
- DPRINTK(("autofs_wait returned %d\n", status));
- if ( status ) {
- iput(dir);
- return status;
- }
- }
- }
+ /* Negative dentry.. Should we time these out? */
+ if (!dentry->d_inode)
+ return dentry;
- DPRINTK(("lookup successful, inode = %08x\n", (unsigned int)ent->ino));
+ /* We should update the usage stuff here.. */
+ return dentry;
+}
- if (!(res = iget(dir->i_sb,ent->ino))) {
- printk("autofs: iget returned null!\n");
- iput(dir);
- return -EACCES;
- }
-
- if ( !oz_mode && S_ISDIR(res->i_mode) && res->i_sb == dir->i_sb ) {
- /* Not a mount point yet, call 1-800-DAEMON */
- DPRINTK(("autofs: waiting on non-mountpoint dir, inode = %lu, pid = %u, pgrp = %u\n", res->i_ino, current->pid, current->pgrp));
- iput(res);
- res = NULL;
- status = autofs_wait(sbi,hash,name,len);
- if ( status ) {
- iput(dir);
- return status;
- }
- }
- } while(!res);
- autofs_update_usage(&sbi->dirhash,ent);
-
- *result = res;
- iput(dir);
+static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
+{
+ struct autofs_sb_info *sbi;
+ struct inode *res;
+ int oz_mode;
+
+ DPRINTK(("autofs_root_lookup: name = "));
+ autofs_say(dentry->d_name.name,dentry->d_name.len);
+
+ if (!S_ISDIR(dir->i_mode))
+ return -ENOTDIR;
+
+ res = NULL;
+ sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
+
+ oz_mode = autofs_oz_mode(sbi);
+ DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n", current->pid, current->pgrp, sbi->catatonic, oz_mode));
+
+ /*
+ * Mark the dentry incomplete, but add it. This is needed so
+ * that the VFS layer knows about the dentry, and we can count
+ * on catching any lookups through the revalidate.
+ *
+ * Let all the hard work be done by the revalidate function that
+ * needs to be able to do this anyway..
+ *
+ * We need to do this before we release the directory semaphore.
+ */
+ dentry->d_revalidate = autofs_revalidate;
+ dentry->d_flags = 1;
+ d_add(dentry, NULL);
+
+ up(&dir->i_sem);
+ autofs_revalidate(dentry);
+ down(&dir->i_sem);
return 0;
}
-static int autofs_root_symlink(struct inode *dir, const char *name, int len, const char *symname)
+static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
struct autofs_dirhash *dh = &sbi->dirhash;
- autofs_hash_t hash = autofs_hash(name,len);
struct autofs_dir_ent *ent;
unsigned int n;
int slsize;
struct autofs_symlink *sl;
DPRINTK(("autofs_root_symlink: %s <- ", symname));
- autofs_say(name,len);
+ autofs_say(dentry->d_name.name,dentry->d_name.len);
- if ( !autofs_oz_mode(sbi) ) {
- iput(dir);
+ if ( !autofs_oz_mode(sbi) )
return -EPERM;
- }
- if ( autofs_hash_lookup(dh,hash,name,len) ) {
- iput(dir);
+
+ if ( autofs_hash_lookup(dh, &dentry->d_name) )
return -EEXIST;
- }
+
n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS);
- if ( n >= AUTOFS_MAX_SYMLINKS ) {
- iput(dir);
+ if ( n >= AUTOFS_MAX_SYMLINKS )
return -ENOSPC;
- }
+
set_bit(n,sbi->symlink_bitmap);
sl = &sbi->symlink[n];
sl->len = strlen(symname);
sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL);
if ( !sl->data ) {
clear_bit(n,sbi->symlink_bitmap);
- iput(dir);
return -ENOSPC;
}
+
ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
if ( !ent ) {
kfree(sl->data);
clear_bit(n,sbi->symlink_bitmap);
- iput(dir);
return -ENOSPC;
}
- ent->name = kmalloc(len, GFP_KERNEL);
+
+ ent->name = kmalloc(dentry->d_name.len, GFP_KERNEL);
if ( !ent->name ) {
kfree(sl->data);
kfree(ent);
clear_bit(n,sbi->symlink_bitmap);
- iput(dir);
return -ENOSPC;
}
+
memcpy(sl->data,symname,slsize);
sl->mtime = CURRENT_TIME;
ent->ino = AUTOFS_FIRST_SYMLINK + n;
- ent->hash = hash;
- memcpy(ent->name,name,ent->len = len);
+ ent->hash = dentry->d_name.hash;
+ memcpy(ent->name, dentry->d_name.name,ent->len = dentry->d_name.len);
autofs_hash_insert(dh,ent);
- iput(dir);
+ d_instantiate(dentry, iget(dir->i_sb,ent->ino));
return 0;
}
-static int autofs_root_unlink(struct inode *dir, const char *name, int len)
+/*
+ * NOTE!
+ *
+ * Normal filesystems would do a "d_delete()" to tell the VFS dcache
+ * that the file no longer exists. However, doing that means that the
+ * VFS layer can turn the dentry into a negative dentry, which we
+ * obviously do not want (we're dropping the entry not because it
+ * doesn't exist, but because it has timed out).
+ *
+ * Also see autofs_root_rmdir()..
+ */
+static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
{
struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
struct autofs_dirhash *dh = &sbi->dirhash;
- autofs_hash_t hash = autofs_hash(name,len);
struct autofs_dir_ent *ent;
unsigned int n;
- iput(dir); /* Nothing below can sleep */
-
if ( !autofs_oz_mode(sbi) )
return -EPERM;
- ent = autofs_hash_lookup(dh,hash,name,len);
+ ent = autofs_hash_lookup(dh, &dentry->d_name);
if ( !ent )
return -ENOENT;
@@ -263,75 +286,68 @@ static int autofs_root_unlink(struct inode *dir, const char *name, int len)
autofs_hash_delete(ent);
clear_bit(n,sbi->symlink_bitmap);
kfree(sbi->symlink[n].data);
+ d_drop(dentry);
return 0;
}
-static int autofs_root_rmdir(struct inode *dir, const char *name, int len)
+static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry)
{
struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
struct autofs_dirhash *dh = &sbi->dirhash;
- autofs_hash_t hash = autofs_hash(name,len);
struct autofs_dir_ent *ent;
- if ( !autofs_oz_mode(sbi) ) {
- iput(dir);
+ if ( !autofs_oz_mode(sbi) )
return -EPERM;
- }
- ent = autofs_hash_lookup(dh,hash,name,len);
- if ( !ent ) {
- iput(dir);
+
+ ent = autofs_hash_lookup(dh, &dentry->d_name);
+ if ( !ent )
return -ENOENT;
- }
- if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO ) {
- iput(dir);
+
+ if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO )
return -ENOTDIR; /* Not a directory */
- }
+
autofs_hash_delete(ent);
dir->i_nlink--;
- iput(dir);
+ d_drop(dentry);
return 0;
}
-static int autofs_root_mkdir(struct inode *dir, const char *name, int len, int mode)
+static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
struct autofs_dirhash *dh = &sbi->dirhash;
- autofs_hash_t hash = autofs_hash(name,len);
struct autofs_dir_ent *ent;
- if ( !autofs_oz_mode(sbi) ) {
- iput(dir);
+ if ( !autofs_oz_mode(sbi) )
return -EPERM;
- }
- ent = autofs_hash_lookup(dh,hash,name,len);
- if ( ent ) {
- iput(dir);
+
+ ent = autofs_hash_lookup(dh, &dentry->d_name);
+ if ( ent )
return -EEXIST;
- }
+
if ( sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO ) {
printk("autofs: Out of inode numbers -- what the heck did you do??\n");
- iput(dir);
return -ENOSPC;
}
+
ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
- if ( !ent ) {
- iput(dir);
+ if ( !ent )
return -ENOSPC;
- }
- ent->name = kmalloc(len, GFP_KERNEL);
+
+ ent->name = kmalloc(dentry->d_name.len, GFP_KERNEL);
if ( !ent->name ) {
kfree(ent);
- iput(dir);
return -ENOSPC;
}
- ent->hash = hash;
- memcpy(ent->name, name, ent->len = len);
+
+ ent->hash = dentry->d_name.hash;
+ memcpy(ent->name, dentry->d_name.name, ent->len = dentry->d_name.len);
ent->ino = sbi->next_dir_ino++;
autofs_hash_insert(dh,ent);
dir->i_nlink++;
- iput(dir);
+ d_instantiate(dentry, iget(dir->i_sb,ent->ino));
return 0;
}
diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c
index d6ac82ed4..e3ff3d31b 100644
--- a/fs/autofs/symlink.c
+++ b/fs/autofs/symlink.c
@@ -19,18 +19,21 @@ static int autofs_readlink(struct inode *inode, char *buffer, int buflen)
struct autofs_symlink *sl;
int len;
- if (!S_ISLNK(inode->i_mode)) {
- iput(inode);
- return -EINVAL;
- }
sl = (struct autofs_symlink *)inode->u.generic_ip;
len = sl->len;
if (len > buflen) len = buflen;
copy_to_user(buffer,sl->data,len);
- iput(inode);
return len;
}
+static struct dentry * autofs_follow_link(struct inode *inode, struct dentry *base)
+{
+ struct autofs_symlink *sl;
+
+ sl = (struct autofs_symlink *)inode->u.generic_ip;
+ return lookup_dentry(sl->data, base, 1);
+}
+
struct inode_operations autofs_symlink_inode_operations = {
NULL, /* file operations */
NULL, /* create */
@@ -43,6 +46,7 @@ struct inode_operations autofs_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
autofs_readlink, /* readlink */
+ autofs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c
index cbe270a53..39beed699 100644
--- a/fs/autofs/waitq.c
+++ b/fs/autofs/waitq.c
@@ -37,7 +37,7 @@ void autofs_catatonic_mode(struct autofs_sb_info *sbi)
wake_up(&wq->queue);
wq = nwq;
}
- fput(sbi->pipe, sbi->pipe->f_inode); /* Close the pipe */
+ fput(sbi->pipe); /* Close the pipe */
}
static int autofs_write(struct file *file, const void *addr, int bytes)
@@ -55,7 +55,7 @@ static int autofs_write(struct file *file, const void *addr, int bytes)
old_signal = current->signal;
- while ( bytes && (written = file->f_op->write(file->f_inode,file,data,bytes)) > 0 ) {
+ while ( bytes && (written = file->f_op->write(file->f_dentry->d_inode,file,data,bytes)) > 0 ) {
data += written;
bytes -= written;
}
@@ -90,15 +90,15 @@ 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, autofs_hash_t hash, const char *name, int len)
+int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name)
{
struct autofs_wait_queue *wq;
int status;
for ( wq = sbi->queues ; wq ; wq = wq->next ) {
- if ( wq->hash == hash &&
- wq->len == len &&
- wq->name && !memcmp(wq->name,name,len) )
+ if ( wq->hash == name->hash &&
+ wq->len == name->len &&
+ wq->name && !memcmp(wq->name,name->name,name->len) )
break;
}
@@ -108,17 +108,17 @@ int autofs_wait(struct autofs_sb_info *sbi, autofs_hash_t hash, const char *name
if ( !wq )
return -ENOMEM;
- wq->name = kmalloc(len,GFP_KERNEL);
+ wq->name = kmalloc(name->len,GFP_KERNEL);
if ( !wq->name ) {
kfree(wq);
return -ENOMEM;
}
wq->wait_queue_token = autofs_next_wait_queue++;
init_waitqueue(&wq->queue);
- wq->hash = hash;
- wq->len = len;
+ wq->hash = name->hash;
+ wq->len = name->len;
wq->status = -EINTR; /* Status return if interrupted */
- memcpy(wq->name, name, len);
+ memcpy(wq->name, name->name, name->len);
wq->next = sbi->queues;
sbi->queues = wq;
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 394f41eb1..c5c7998cf 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -79,6 +79,7 @@ if (file.f_op->llseek) { \
static inline int
do_aout_core_dump(long signr, struct pt_regs * regs)
{
+ struct dentry * dentry = NULL;
struct inode * inode = NULL;
struct file file;
unsigned short fs;
@@ -114,26 +115,20 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
#else
corefile[4] = '\0';
#endif
- if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
- inode = NULL;
+ dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC, 0600);
+ if (IS_ERR(dentry)) {
+ dentry = NULL;
goto end_coredump;
}
+ inode = dentry->d_inode;
if (!S_ISREG(inode->i_mode))
goto end_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto end_coredump;
if (get_write_access(inode))
goto end_coredump;
- file.f_mode = 3;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_inode = inode;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto done_coredump;
+ if (init_private_file(&file, dentry, 3))
+ goto end_coredump;
if (!file.f_op->write)
goto close_coredump;
has_dumped = 1;
@@ -214,7 +209,6 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
/* Finally dump the task struct. Not be used by gdb, but could be useful */
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
- inode->i_status |= ST_MODIFIED;
close_coredump:
if (file.f_op->release)
file.f_op->release(inode,&file);
@@ -222,7 +216,7 @@ done_coredump:
put_write_access(inode);
end_coredump:
set_fs(fs);
- iput(inode);
+ dput(dentry);
return has_dumped;
}
@@ -318,7 +312,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
@@ -332,7 +326,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
}
if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
- (fd_offset < bprm->inode->i_sb->s_blocksize)) {
+ (fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
return -ENOEXEC;
}
@@ -372,12 +366,12 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
- read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+ read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
ex.a_text, 0);
error = do_mmap(NULL, N_DATADDR(ex), ex.a_data,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
- read_exec(bprm->inode, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
+ read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
ex.a_data, 0);
goto beyond_if;
}
@@ -389,20 +383,20 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
ex.a_text+ex.a_data + PAGE_SIZE - 1,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
- read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+ read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
ex.a_text+ex.a_data, 0);
#else
do_mmap(NULL, 0, ex.a_text+ex.a_data,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
- read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data, 0);
+ read_exec(bprm->dentry, 32, (char *) 0, ex.a_text+ex.a_data, 0);
#endif
} else {
if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
(N_MAGIC(ex) != NMAGIC))
printk(KERN_NOTICE "executable not page aligned\n");
- fd = open_inode(bprm->inode, O_RDONLY);
+ fd = open_dentry(bprm->dentry, O_RDONLY);
if (fd < 0)
return fd;
@@ -412,7 +406,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
do_mmap(NULL, 0, ex.a_text+ex.a_data,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
- read_exec(bprm->inode, fd_offset,
+ read_exec(bprm->dentry, fd_offset,
(char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
goto beyond_if;
}
@@ -482,18 +476,21 @@ do_load_aout_library(int fd)
{
struct file * file;
struct exec ex;
- struct inode * inode;
+ struct dentry * dentry;
+ struct inode * inode;
unsigned int len;
unsigned int bss;
unsigned int start_addr;
unsigned long error;
file = current->files->fd[fd];
- inode = file->f_inode;
if (!file || !file->f_op)
return -EACCES;
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
+
/* Seek into the file */
if (file->f_op->llseek) {
if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index ff987e0e8..7629fd0d8 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -134,23 +134,20 @@ create_elf_tables(char *p, int argc, int envc,
{
elf_caddr_t *argv;
elf_caddr_t *envp;
- elf_addr_t *sp;
+ elf_addr_t *sp, *csp;
/*
- * Force 16 byte alignment here for generality.
+ * Force 16 byte _final_ alignment here for generality.
*/
sp = (elf_addr_t *) (~15UL & (unsigned long) p);
-#if defined(__mips__) || defined(__sparc__)
-{
- elf_addr_t *csp;
csp = sp;
csp -= exec ? DLINFO_ITEMS*2 : 2;
csp -= envc+1;
csp -= argc+1;
- if (!(((unsigned long) csp) & 4))
- sp--;
-}
-#endif
+ csp -= (!ibcs ? 3 : 1); /* argc itself */
+ if ((unsigned long)csp & 15UL) {
+ sp -= (16UL - ((unsigned long)csp & 15UL)) / sizeof(*sp);
+ }
/*
* Put the ELF interpreter info on the stack
@@ -165,17 +162,17 @@ create_elf_tables(char *p, int argc, int envc,
if (exec) {
sp -= 11*2;
- NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
- NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
- NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
- NEW_AUX_ENT (3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
- NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
- NEW_AUX_ENT (5, AT_FLAGS, 0);
- NEW_AUX_ENT (6, AT_ENTRY, (elf_addr_t) exec->e_entry);
- NEW_AUX_ENT (7, AT_UID, (elf_addr_t) current->uid);
- NEW_AUX_ENT (8, AT_EUID, (elf_addr_t) current->euid);
- NEW_AUX_ENT (9, AT_GID, (elf_addr_t) current->gid);
- NEW_AUX_ENT (10, AT_EGID, (elf_addr_t) current->egid);
+ NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
+ NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
+ NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
+ NEW_AUX_ENT (3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
+ NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
+ NEW_AUX_ENT (5, AT_FLAGS, 0);
+ NEW_AUX_ENT (6, AT_ENTRY, (elf_addr_t) exec->e_entry);
+ NEW_AUX_ENT (7, AT_UID, (elf_addr_t) current->uid);
+ NEW_AUX_ENT (8, AT_EUID, (elf_addr_t) current->euid);
+ NEW_AUX_ENT (9, AT_GID, (elf_addr_t) current->gid);
+ NEW_AUX_ENT (10, AT_EGID, (elf_addr_t) current->egid);
}
#undef NEW_AUX_ENT
@@ -212,7 +209,7 @@ create_elf_tables(char *p, int argc, int envc,
an ELF header */
static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
- struct inode * interpreter_inode,
+ struct dentry * interpreter_dentry,
unsigned long *interp_load_addr)
{
struct file * file;
@@ -234,8 +231,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
if ((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) ||
!elf_check_arch(interp_elf_ex->e_machine) ||
- (!interpreter_inode->i_op ||
- !interpreter_inode->i_op->default_file_ops->mmap)){
+ (!interpreter_dentry->d_inode->i_op ||
+ !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)){
+
#ifdef DEBUG_ELF
printk("bad e_type %d ", interp_elf_ex->e_type);
#endif
@@ -265,7 +263,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
return ~0UL;
}
- retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
+ retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
(char *) elf_phdata,
sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
@@ -274,7 +272,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
return retval;
}
- elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
+ elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
if (elf_exec_fileno < 0) {
kfree(elf_phdata);
return ~0UL;
@@ -366,7 +364,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
}
static unsigned long load_aout_interp(struct exec * interp_ex,
- struct inode * interpreter_inode)
+ struct dentry * interpreter_dentry)
{
int retval;
unsigned long elf_entry;
@@ -381,13 +379,13 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode, 32, (char *) 0,
+ retval = read_exec(interpreter_dentry, 32, (char *) 0,
interp_ex->a_text+interp_ex->a_data, 0);
} else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode,
+ retval = read_exec(interpreter_dentry,
N_TXTOFF(*interp_ex) ,
(char *) N_TXTADDR(*interp_ex),
interp_ex->a_text+interp_ex->a_data, 0);
@@ -422,7 +420,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
struct elfhdr interp_elf_ex;
struct file * file;
struct exec interp_ex;
- struct inode *interpreter_inode;
+ struct dentry *interpreter_dentry;
unsigned long load_addr;
int load_addr_set = 0;
unsigned int interpreter_type = INTERPRETER_NONE;
@@ -456,8 +454,8 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if ((elf_ex.e_type != ET_EXEC &&
elf_ex.e_type != ET_DYN) ||
(! elf_check_arch(elf_ex.e_machine)) ||
- (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
- !bprm->inode->i_op->default_file_ops->mmap)){
+ (!bprm->dentry->d_inode->i_op || !bprm->dentry->d_inode->i_op->default_file_ops ||
+ !bprm->dentry->d_inode->i_op->default_file_ops->mmap)){
return -ENOEXEC;
}
@@ -475,7 +473,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
return -ENOMEM;
}
- retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
+ retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata,
elf_ex.e_phentsize * elf_ex.e_phnum, 1);
if (retval < 0) {
kfree (elf_phdata);
@@ -487,7 +485,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
elf_bss = 0;
elf_brk = 0;
- elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
+ elf_exec_fileno = open_dentry(bprm->dentry, O_RDONLY);
if (elf_exec_fileno < 0) {
kfree (elf_phdata);
@@ -525,7 +523,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
return -ENOMEM;
}
- retval = read_exec(bprm->inode,elf_ppnt->p_offset,
+ retval = read_exec(bprm->dentry,elf_ppnt->p_offset,
elf_interpreter,
elf_ppnt->p_filesz, 1);
/* If the program interpreter is one of these two,
@@ -540,13 +538,14 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (retval >= 0) {
old_fs = get_fs(); /* This could probably be optimized */
set_fs(get_ds());
- retval = open_namei(elf_interpreter, 0, 0,
- &interpreter_inode, NULL);
+ interpreter_dentry = open_namei(elf_interpreter, 0, 0);
set_fs(old_fs);
+ if (IS_ERR(interpreter_dentry))
+ retval = PTR_ERR(interpreter_dentry);
}
if (retval >= 0)
- retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
+ retval = read_exec(interpreter_dentry,0,bprm->buf,128, 1);
if (retval >= 0) {
interp_ex = *((struct exec *) bprm->buf); /* exec-header */
@@ -682,13 +681,13 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (elf_interpreter) {
if (interpreter_type & 1)
elf_entry = load_aout_interp(&interp_ex,
- interpreter_inode);
+ interpreter_dentry);
else if (interpreter_type & 2)
elf_entry = load_elf_interp(&interp_elf_ex,
- interpreter_inode,
+ interpreter_dentry,
&interp_load_addr);
- iput(interpreter_inode);
+ dput(interpreter_dentry);
kfree(elf_interpreter);
if (elf_entry == ~0UL) {
@@ -716,8 +715,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
__MOD_INC_USE_COUNT(current->binfmt->module);
#ifndef VM_STACK_FLAGS
- current->executable = bprm->inode;
- atomic_inc(&bprm->inode->i_count);
+ current->executable = dget(bprm->dentry);
#endif
#ifdef LOW_ELF_STACK
current->start_stack = bprm->p = elf_stack - 4;
@@ -802,7 +800,8 @@ do_load_elf_library(int fd){
struct file * file;
struct elfhdr elf_ex;
struct elf_phdr *elf_phdata = NULL;
- struct inode * inode;
+ struct dentry * dentry;
+ struct inode * inode;
unsigned long len;
int elf_bss;
int retval;
@@ -812,7 +811,8 @@ do_load_elf_library(int fd){
len = 0;
file = current->files->fd[fd];
- inode = file->f_inode;
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
elf_bss = 0;
if (!file || !file->f_op)
@@ -851,7 +851,7 @@ do_load_elf_library(int fd){
if (elf_phdata == NULL)
return -ENOMEM;
- retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
+ retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata,
sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
j = 0;
@@ -923,14 +923,13 @@ static int load_elf_library(int fd)
*/
static int dump_write(struct file *file, const void *addr, int nr)
{
- file->f_inode->i_status |= ST_MODIFIED;
- return file->f_op->write(file->f_inode, file, addr, nr) == nr;
+ return file->f_op->write(file->f_dentry->d_inode, file, addr, nr) == nr;
}
static int dump_seek(struct file *file, off_t off)
{
if (file->f_op->llseek) {
- if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
+ if (file->f_op->llseek(file->f_dentry->d_inode, file, off, 0) != off)
return 0;
} else
file->f_pos = off;
@@ -1045,6 +1044,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
{
int has_dumped = 0;
struct file file;
+ struct dentry *dentry;
struct inode *inode;
unsigned short fs;
char corefile[6+sizeof(current->comm)];
@@ -1118,24 +1118,18 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
#else
corefile[4] = '\0';
#endif
- if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
- inode = NULL;
+ dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600);
+ if (IS_ERR(dentry)) {
+ dentry = NULL;
goto end_coredump;
}
+ inode = dentry->d_inode;
if (!S_ISREG(inode->i_mode))
goto end_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto end_coredump;
- file.f_mode = 3;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_inode = inode;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto end_coredump;
+ if (init_private_file(&file, dentry, 3))
+ goto end_coredump;
if (!file.f_op->write)
goto close_coredump;
has_dumped = 1;
@@ -1326,7 +1320,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
end_coredump:
set_fs(fs);
- iput(inode);
+ dput(dentry);
#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
#endif
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index 7bd71f212..133586e69 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -23,6 +23,7 @@
static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
{
char *interp, *i_name, *i_arg;
+ struct dentry * dentry;
int retval;
struct elfhdr elf_ex;
@@ -39,14 +40,14 @@ static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
if ((elf_ex.e_type != ET_EXEC &&
elf_ex.e_type != ET_DYN) ||
(!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
- (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
- !bprm->inode->i_op->default_file_ops->mmap)){
+ (!bprm->dentry->d_inode->i_op || !bprm->dentry->d_inode->i_op->default_file_ops ||
+ !bprm->dentry->d_inode->i_op->default_file_ops->mmap)){
return -ENOEXEC;
}
bprm->sh_bang++; /* Well, the bang-shell is implicit... */
- iput(bprm->inode);
- bprm->dont_iput = 1;
+ dput(bprm->dentry);
+ bprm->dentry = NULL;
/* Unlike in the script case, we don't have to do any hairy
* parsing to find our interpreter... it's hardcoded!
@@ -79,14 +80,17 @@ static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
* Note that we use open_namei() as the name is now in kernel
* space, and we don't need to copy it.
*/
- retval = open_namei(interp, 0, 0, &bprm->inode, NULL);
- if (retval)
- return retval;
- bprm->dont_iput=0;
- retval=prepare_binprm(bprm);
- if(retval<0)
+ dentry = open_namei(interp, 0, 0);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
+ bprm->dentry = dentry;
+
+ retval = prepare_binprm(bprm);
+ if (retval < 0)
return retval;
- return search_binary_handler(bprm,regs);
+
+ return search_binary_handler(bprm, regs);
}
static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
diff --git a/fs/binfmt_java.c b/fs/binfmt_java.c
index fcf664c5d..41e66a21a 100644
--- a/fs/binfmt_java.c
+++ b/fs/binfmt_java.c
@@ -28,7 +28,9 @@ static int do_load_java(struct linux_binprm *bprm,struct pt_regs *regs)
char *i_name;
int len;
int retval;
+ struct dentry * dentry;
unsigned char *ucp = (unsigned char *) bprm->buf;
+
if ((ucp[0] != 0xca) || (ucp[1] != 0xfe) || (ucp[2] != 0xba) || (ucp[3] != 0xbe))
return -ENOEXEC;
@@ -42,8 +44,8 @@ static int do_load_java(struct linux_binprm *bprm,struct pt_regs *regs)
bprm->java = 1;
- iput(bprm->inode);
- bprm->dont_iput=1;
+ dput(bprm->dentry);
+ bprm->dentry = NULL;
/*
* Set args: [0] the name of the java interpreter
@@ -75,15 +77,17 @@ static int do_load_java(struct linux_binprm *bprm,struct pt_regs *regs)
if (!bprm->p)
return -E2BIG;
/*
- * OK, now restart the process with the interpreter's inode.
+ * OK, now restart the process with the interpreter's dentry.
*/
bprm->filename = binfmt_java_interpreter;
- retval = open_namei(binfmt_java_interpreter, 0, 0, &bprm->inode, NULL);
- if (retval)
+ dentry = open_namei(binfmt_java_interpreter, 0, 0);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
return retval;
- bprm->dont_iput=0;
- retval=prepare_binprm(bprm);
- if(retval<0)
+
+ bprm->dentry = dentry;
+ retval = prepare_binprm(bprm);
+ if (retval < 0)
return retval;
return search_binary_handler(bprm,regs);
@@ -92,12 +96,14 @@ static int do_load_java(struct linux_binprm *bprm,struct pt_regs *regs)
static int do_load_applet(struct linux_binprm *bprm,struct pt_regs *regs)
{
char *i_name;
+ struct dentry * dentry;
int retval;
+
if (strncmp (bprm->buf, "<!--applet", 10))
return -ENOEXEC;
- iput(bprm->inode);
- bprm->dont_iput=1;
+ dput(bprm->dentry);
+ bprm->dentry = NULL;
/*
* Set args: [0] the name of the appletviewer
@@ -118,15 +124,17 @@ static int do_load_applet(struct linux_binprm *bprm,struct pt_regs *regs)
if (!bprm->p)
return -E2BIG;
/*
- * OK, now restart the process with the interpreter's inode.
+ * OK, now restart the process with the interpreter's dentry.
*/
bprm->filename = binfmt_java_appletviewer;
- retval = open_namei(binfmt_java_appletviewer, 0, 0, &bprm->inode, NULL);
- if (retval)
+ dentry = open_namei(binfmt_java_appletviewer, 0, 0);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
return retval;
- bprm->dont_iput=0;
- retval=prepare_binprm(bprm);
- if(retval<0)
+
+ bprm->dentry = dentry;
+ retval = prepare_binprm(bprm);
+ if (retval < 0)
return retval;
return search_binary_handler(bprm,regs);
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 28dced394..ffca300d9 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -7,9 +7,11 @@
* a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
* binfmt_mz.
*
- * 25.4.97 first version
- * [...]
- * 19.5.97 cleanup
+ * 1997-04-25 first version
+ * [...]
+ * 1997-05-19 cleanup
+ * 1997-06-26 hpa: pass the real filename rather than argv[0]
+ * 1997-06-30 minor cleanup
*/
#include <linux/module.h>
@@ -48,7 +50,7 @@ struct binfmt_entry {
#define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */
#define ENTRY_MAGIC 8 /* not filename detection */
-#define ENTRY_STRIP_EXT 32 /* strip of last filename extension */
+#define ENTRY_STRIP_EXT 32 /* strip off last filename extension */
static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
static void entry_proc_cleanup(struct binfmt_entry *e);
@@ -85,7 +87,6 @@ static void clear_entry(int id)
*ep = e->next;
entry_proc_cleanup(e);
kfree(e);
- MOD_DEC_USE_COUNT;
}
write_unlock(&entries_lock);
}
@@ -102,7 +103,6 @@ static void clear_entries(void)
entries = entries->next;
entry_proc_cleanup(e);
kfree(e);
- MOD_DEC_USE_COUNT;
}
write_unlock(&entries_lock);
}
@@ -157,6 +157,7 @@ static struct binfmt_entry *check_file(struct linux_binprm *bprm)
static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
{
struct binfmt_entry *fmt;
+ struct dentry * dentry;
char iname[128];
char *iname_addr = iname, *p;
int retval, fmt_flags = 0;
@@ -180,17 +181,16 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
goto _ret;
}
- iput(bprm->inode);
- bprm->dont_iput = 1;
+ dput(bprm->dentry);
+ bprm->dentry = NULL;
/* Build args for interpreter */
if ((fmt_flags & ENTRY_STRIP_EXT) &&
- (p = strrchr(bprm->filename, '.'))) {
+ (p = strrchr(bprm->filename, '.')))
*p = '\0';
- remove_arg_zero(bprm);
- bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
- bprm->argc++;
- }
+ remove_arg_zero(bprm);
+ bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
+ bprm->argc++;
bprm->p = copy_strings(1, &iname_addr, bprm->page, bprm->p, 2);
bprm->argc++;
if (!bprm->p) {
@@ -199,11 +199,14 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
}
bprm->filename = iname; /* for binfmt_script */
- if ((retval = open_namei(iname, 0, 0, &bprm->inode, NULL)))
+ dentry = open_namei(iname, 0, 0);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto _ret;
- bprm->dont_iput = 0;
+ bprm->dentry = dentry;
- if ((retval = prepare_binprm(bprm)) >= 0)
+ retval = prepare_binprm(bprm);
+ if (retval >= 0)
retval = search_binary_handler(bprm, regs);
_ret:
MOD_DEC_USE_COUNT;
@@ -322,7 +325,7 @@ static int proc_write_register(struct file *file, const char *buffer,
entries = e;
write_unlock(&entries_lock);
- return count;
+ err = count;
_err:
MOD_DEC_USE_COUNT;
return err;
@@ -499,6 +502,7 @@ void cleanup_module(void)
unregister_binfmt(&misc_format);
remove_proc_entry("register", bm_dir);
remove_proc_entry("status", bm_dir);
+ clear_entries();
remove_proc_entry("sys/fs/binfmt_misc", NULL);
}
#endif
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index 1bd2f0d10..5a38cf545 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -15,8 +15,10 @@
static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
{
char *cp, *i_name, *i_name_start, *i_arg;
+ struct dentry * dentry;
char interp[128];
int retval;
+
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang))
return -ENOEXEC;
/*
@@ -25,8 +27,8 @@ static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
*/
bprm->sh_bang++;
- iput(bprm->inode);
- bprm->dont_iput=1;
+ dput(bprm->dentry);
+ bprm->dentry = NULL;
bprm->buf[127] = '\0';
if ((cp = strchr(bprm->buf, '\n')) == NULL)
@@ -75,14 +77,15 @@ static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
if (!bprm->p)
return -E2BIG;
/*
- * OK, now restart the process with the interpreter's inode.
+ * OK, now restart the process with the interpreter's dentry.
*/
- retval = open_namei(interp, 0, 0, &bprm->inode, NULL);
- if (retval)
- return retval;
- bprm->dont_iput=0;
- retval=prepare_binprm(bprm);
- if(retval<0)
+ dentry = open_namei(interp, 0, 0);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
+ bprm->dentry = dentry;
+ retval = prepare_binprm(bprm);
+ if (retval < 0)
return retval;
return search_binary_handler(bprm,regs);
}
diff --git a/fs/buffer.c b/fs/buffer.c
index bd06972f3..3e1b5cc35 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -289,16 +289,35 @@ int file_fsync (struct inode *inode, struct file *filp)
asmlinkage int sys_fsync(unsigned int fd)
{
struct file * file;
+ struct dentry * dentry;
struct inode * inode;
- int err = 0;
+ int err;
lock_kernel();
- if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
- err = -EBADF;
- else if (!file->f_op || !file->f_op->fsync)
- err = -EINVAL;
- else if (file->f_op->fsync(inode,file))
- err = -EIO;
+ err = -EBADF;
+
+ if (fd >= NR_OPEN)
+ goto out;
+
+ file = current->files->fd[fd];
+ if (!file)
+ goto out;
+
+ dentry = file->f_dentry;
+ if (!dentry)
+ goto out;
+
+ inode = dentry->d_inode;
+ if (!inode)
+ goto out;
+
+ err = -EINVAL;
+ if (!file->f_op || !file->f_op->fsync)
+ goto out;
+
+ err = file->f_op->fsync(inode,file);
+
+out:
unlock_kernel();
return err;
}
@@ -306,20 +325,35 @@ asmlinkage int sys_fsync(unsigned int fd)
asmlinkage int sys_fdatasync(unsigned int fd)
{
struct file * file;
+ struct dentry * dentry;
struct inode * inode;
- int err = -EBADF;
+ int err;
lock_kernel();
- if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
+ err = -EBADF;
+
+ if (fd >= NR_OPEN)
+ goto out;
+
+ file = current->files->fd[fd];
+ if (!file)
+ goto out;
+
+ dentry = file->f_dentry;
+ if (!dentry)
goto out;
+
+ inode = dentry->d_inode;
+ if (!inode)
+ goto out;
+
err = -EINVAL;
if (!file->f_op || !file->f_op->fsync)
goto out;
+
/* this needs further work, at the moment it is identical to fsync() */
- if (file->f_op->fsync(inode,file))
- err = -EIO;
- else
- err = 0;
+ err = file->f_op->fsync(inode,file);
+
out:
unlock_kernel();
return err;
@@ -495,17 +529,18 @@ static inline void insert_into_queues(struct buffer_head * bh)
static inline struct buffer_head * find_buffer(kdev_t dev, int block, int size)
{
- struct buffer_head * tmp;
-
- for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
- if (tmp->b_blocknr == block && tmp->b_dev == dev) {
- if (tmp->b_size == size)
- return tmp;
+ struct buffer_head * next;
- printk("VFS: Wrong blocksize on device %s\n",
- kdevname(dev));
- return NULL;
- }
+ next = hash(dev,block);
+ for (;;) {
+ struct buffer_head *tmp = next;
+ if (!next)
+ break;
+ next = tmp->b_next;
+ if (tmp->b_blocknr != block || tmp->b_size != size || tmp->b_dev != dev)
+ continue;
+ return tmp;
+ }
return NULL;
}
@@ -518,10 +553,11 @@ static inline struct buffer_head * find_buffer(kdev_t dev, int block, int size)
*/
struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
{
- struct buffer_head * bh;
-
for (;;) {
- if (!(bh=find_buffer(dev,block,size)))
+ struct buffer_head * bh;
+
+ bh=find_buffer(dev,block,size);
+ if (!bh)
return NULL;
bh->b_count++;
wait_on_buffer(bh);
@@ -1610,6 +1646,7 @@ asmlinkage int sync_old_buffers(void)
next->b_count--;
}
}
+ 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);
diff --git a/fs/dcache.c b/fs/dcache.c
index 0472487e0..395aed829 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -5,1035 +5,341 @@
* (C) 1997 Thomas Schoebel-Theuer
*/
-/* The new dcache is exclusively called from the VFS, not from
- * the specific fs'es any more. Despite having the same name as in the
- * old code, it has less to do with it.
- *
- * It serves many purposes:
- *
- * 1) Any inode that has been retrieved with lookup() and is in use
- * (i_count>0), has access to its full absolute path name, by going
- * to inode->i_dentry and then recursively following the entry->d_parent
- * chain. Use d_path() as predefined method for that.
- * You may find out the corresponding inode belonging to
- * a dentry by calling d_inode(). This can be used as an easy way for
- * determining .. and its absolute pathname, an old UNIX problem that
- * deserved a solution for a long time.
- * Note that hardlinked inodes may have multiple dentries assigned to
- * (via the d_next chain), reflecting multiple alias pathnames.
- *
- * 2) If not disabled by filesystem types specifying FS_NO_DCACHE,
- * the dentries of unused (aged) inodes are retained for speeding up
- * lookup()s, by allowing hashed inquiry starting from the dentry of
- * the parent directory.
- *
- * 3) It can remeber so-called "negative entries", that is dentries for
- * pathnames that are known to *not* exist, so unneccessary repeated
- * lookup()s for non-existant names can be saved.
- *
- * 4) It provides a means for keeping deleted files (inode->i_nlink==0)
- * accessible in the so-called *basket*. Inodes in the basket have been
- * removed with unlink() while being in use (i_count>0), so they would
- * normally use up space on the disk and be accessile through their
- * filedescriptor, but would not be accessible for lookup() any more.
- * The basket simply keeps such files in the dcache (for potential
- * dcache lookup) until they are either eventually removed completely,
- * or transferred to the second-level basket, the so-called *ibasket*.
- * The ibasket is implemented in the new inode code, on request of
- * filesystem types that have the flag FS_IBASKET set, and proliferates
- * the unlinked files when i_count has gone to zero, at least as long
- * as there is space on the disk and enough inodes remain available
- * and no umount() has started.
- *
- * 5) Preliminary dentries can be added by readdir(). While normal dentries
- * directly point to the inode via u.d_inode only the inode number is
- * known from readdir(), but not more. They can be converted to
- * normal dentries by using d_inode().
- */
-
/*
* Notes on the allocation strategy:
*
- * The dcache is a full slave cache of the inodes. Whenever an inode
- * is cleared, all the dentries associated with it will recursively
- * disappear. dentries have no own reference counting; this has to
- * be obeyed for SMP.
- * If directories could go out of inode cache while
- * successors are alive, this would interrupt the d_parent chain of
- * the live successors. To prevent this without using zombies, all
- * directories are thus prevented from __iput() as long as successors
- * are alive.
+ * The dcache is a master of the icache - whenever a dcache entry
+ * exists, the inode will always exist. "iput()" is done either when
+ * the dcache entry is deleted or garbage collected.
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/fs.h>
-#include <linux/dalloc.h>
-#include <linux/dlists.h>
-
-/* this should be removed after the beta phase */
-/* #define DEBUG */
-/*#undef DEBUG*/
-/* #define DEBUG_DDIR_COUNT */
-
-#define D_HASHSIZE 64
-
-/* local flags for d_flag */
-#define D_DIR 32
-#define D_HASHED 64
-#define D_ZOMBIE 128
-#define D_PRELIMINARY 256
-#define D_INC_DDIR 512
-
-/* local flags for d_del() */
-#define D_RECURSIVE 4
-#define D_NO_FREE 8
-
-/* adjust these constants if you know a probability distribution ... */
-#define D_SMALL 16
-#define D_MEDIUM 64
-#define D_LARGE 256
-#define D_HUGE D_MAXLEN
+#include <linux/malloc.h>
-#define BASE_DHEADER(x) (struct dheader*)((unsigned long)(x) & ~(PAGE_SIZE-1))
-#define BYTE_ADD(x,n) (void*)((char*)(x) + (n))
-#define BYTE_SUB(x,n) (void*)((char*)(x) - (n))
-
-/* This is for global allocation of dentries. Remove this when
- * converting to SLAB.
- */
-struct dheader {
- struct dentry * emptylist;
- short free, maxfree;
- struct dheader * next;
- struct dheader * prev;
-};
-
-struct anchors {
- struct dheader * free; /* each contains at least 1 empty dentry */
- struct dheader * full; /* all the used up ones */
- struct dheader * dir_free;
- struct dheader * dir_full;
-};
-
-/* This is only used for directory dentries. Think of it as an extension
- * of the dentry.
- * It is defined as separate struct, so it uses up space only
- * where necessary.
+/*
+ * This is the single most critical data structure when it comes
+ * to the dcache: the hashtable for lookups. Somebody should try
+ * to make this good - I've just made it work.
+ *
+ * This hash-function tries to avoid losing too many bits of hash
+ * information, yet avoid using a prime hash-size or similar.
*/
-struct ddir {
- struct dentry * dd_hashtable[D_HASHSIZE];
- struct dentry * dd_neglist;
- struct dentry * dd_basketlist;
- struct dentry * dd_zombielist;
- unsigned short dd_alloced; /* # d_alloc()ed, but not yet d_add()ed */
- unsigned short dd_hashed; /* # of entries in hashtable */
- unsigned short dd_true_hashed; /* # non-preliminaries in hashtable */
- unsigned short dd_negs; /* # of negative entries */
-};
-
-DEF_INSERT(header,struct dheader,next,prev)
-DEF_REMOVE(header,struct dheader,next,prev)
+#define D_HASHBITS 10
+#define D_HASHSIZE (1UL << D_HASHBITS)
+#define D_HASHMASK (D_HASHSIZE-1)
-DEF_INSERT(alias,struct dentry,d_next,d_prev)
-DEF_REMOVE(alias,struct dentry,d_next,d_prev)
+static struct list_head dentry_hashtable[D_HASHSIZE];
+static LIST_HEAD(dentry_unused);
-DEF_INSERT(hash,struct dentry,d_hash_next,d_hash_prev)
-DEF_REMOVE(hash,struct dentry,d_hash_next,d_hash_prev)
-
-DEF_INSERT(basket,struct dentry,d_basket_next,d_basket_prev)
-DEF_REMOVE(basket,struct dentry,d_basket_next,d_basket_prev)
-
-static struct anchors anchors[4];
-
-struct dentry * the_root = NULL;
-
-unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end)
+void d_free(struct dentry *dentry)
{
- memset(anchors, 0, sizeof(anchors));
- return mem_start;
+ kfree(dentry->d_name.name);
+ kfree(dentry);
}
-#ifdef DEBUG
-/* throw this away after the beta phase */
-/*************************************************************************/
-extern void xcheck(char * txt, struct inode * p);
-
-static int x_alloc = 0;
-static int x_freed = 0;
-static int x_free = 0;
-
-static void * tst[20000];
-static int cnt = 0;
-
-static void ins(void* ptr)
-{
- extern int inodes_stat;
- tst[cnt++] = ptr;
- if(cnt % 1000 == 0)
- printk("------%d allocated: %d: %d %d %d\n", inodes_stat, cnt,
- x_alloc, x_freed, x_free);
- if(cnt>=20000) panic("stop");
-}
-
-#if 0
-static inline int search(void* ptr)
-{
- int i;
- for(i = cnt-1; i>=0; i--)
- if(tst[i] == ptr)
- return i;
- return -1;
-}
-
-#define TST(n,x) if(search(x)<0) printk("%s bad ptr %p line %d\n", n, x, __LINE__)
-#else
-#define TST(n,x) /*nothing*/
-#endif
-
-void LOG(char * txt, struct dentry * entry)
-{
- static int count = 0;
- if(entry) {
- TST(txt,entry);
- }
- if(count) {
- count--;
- printk("%s: entry=%p\n", txt, entry);
- }
-}
-
-#ifdef DEBUG_DDIR_COUNT
-static struct ddir * d_dir(struct dentry * entry);
-void recursive_test(struct dentry * entry)
-{
- int i;
- struct ddir * ddir = d_dir(entry);
- int sons = 0;
-
- if(ddir->dd_zombielist)
- sons++;
- for(i=0; i < D_HASHSIZE; i++) {
- struct dentry ** base = &ddir->dd_hashtable[i];
- struct dentry * tmp = *base;
- if(tmp) do {
- TST("__clear",tmp);
- if(!(tmp->d_flag & D_HASHED)) {
- printk("VFS: dcache entry not hashed!\n");
- printpath(*base); printk("\n");
- printpath(tmp);
- }
- if(!(tmp->d_flag & D_PRELIMINARY))
- sons++;
- if(tmp->d_flag & D_DIR)
- recursive_test(tmp);
- tmp = tmp->d_hash_next;
- } while(tmp && tmp != *base);
- }
- if(!sons && !(entry->d_flag & D_PRELIMINARY) && entry->u.d_inode) {
- struct inode * inode = entry->u.d_inode;
- if(!atomic_read(&inode->i_count)) {
- if(!(inode->i_status & 1/*ST_AGED*/)) {
- printpath(entry);
- printk(" is not aged!\n");
- }
- if(inode->i_ddir_count) {
- printpath(entry);
- printk(" has ddir_count blockage!\n");
+/*
+ * dput()
+ *
+ * This is complicated by the fact that we do not want to put
+ * dentries that are no longer on any hash chain on the unused
+ * list: we'd much rather just get rid of them immediately.
+ *
+ * However, that implies that we have to traverse the dentry
+ * tree upwards to the parents which might _also_ now be
+ * scheduled for deletion (it may have been only waiting for
+ * its last child to go away).
+ *
+ * This tail recursion is done by hand as we don't want to depend
+ * on the compiler to always get this right (gcc generally doesn't).
+ * Real recursion would eat up our stack space.
+ */
+void dput(struct dentry *dentry)
+{
+ if (dentry) {
+ int count;
+repeat:
+ count = dentry->d_count-1;
+ if (count < 0) {
+ printk("Negative d_count (%d) for %s/%s\n",
+ count,
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
+ *(int *)0 = 0;
+ }
+ dentry->d_count = count;
+ if (!count) {
+ list_del(&dentry->d_lru);
+ if (list_empty(&dentry->d_hash)) {
+ struct inode *inode = dentry->d_inode;
+ struct dentry * parent;
+ if (inode) {
+ list_del(&dentry->d_alias);
+ iput(inode);
+ }
+ parent = dentry->d_parent;
+ d_free(dentry);
+ if (dentry == parent)
+ return;
+ dentry = parent;
+ goto repeat;
}
+ list_add(&dentry->d_lru, &dentry_unused);
}
}
}
-#else
-#define recursive_test(e) /*nothing*/
-#endif
-#else
-#define TST(n,x) /*nothing*/
-#define LOG(n,x) /*nothing*/
-#define xcheck(t,i) /*nothing*/
-#define recursive_test(e) /*nothing*/
-/*****************************************************************************/
-#endif
-void printpath(struct dentry * entry)
-{
- if(!IS_ROOT(entry))
- printpath(entry->d_parent);
- printk("/%s", entry->d_name);
-}
-
-static inline long has_sons(struct ddir * ddir)
-{
- return ((ddir->dd_alloced | ddir->dd_hashed) ||
- ddir->dd_neglist ||
- ddir->dd_basketlist ||
- ddir->dd_zombielist);
-}
-
-static inline int has_true_sons(struct ddir * ddir)
-{
- return (ddir->dd_alloced | ddir->dd_true_hashed);
-}
-
-/* Only hold the i_ddir_count pseudo refcount when neccessary (i.e. when
- * they have true_sons), to prevent keeping too much dir inodes in use.
+/*
+ * Shrink the dcache. This is done when we need
+ * more memory, or simply when we need to unmount
+ * something (at which point we need to unuse
+ * all dentries).
*/
-static inline void inc_ddir(struct dentry * entry, struct inode * inode)
-{
- if(!(entry->d_flag & D_INC_DDIR)) {
- entry->d_flag |= D_INC_DDIR;
-#ifdef DEBUG
- if(inode->i_ddir_count) {
- printpath(entry);
- printk(" ddir_count=%d\n", inode->i_ddir_count);
+void shrink_dcache(void)
+{
+ for (;;) {
+ struct dentry *dentry;
+ struct list_head *tmp = dentry_unused.prev;
+
+ if (tmp == &dentry_unused)
+ break;
+ list_del(tmp);
+ INIT_LIST_HEAD(tmp);
+ dentry = list_entry(tmp, struct dentry, d_lru);
+ if (!dentry->d_count) {
+ struct dentry * parent;
+
+ list_del(&dentry->d_hash);
+ if (dentry->d_inode) {
+ struct inode * inode = dentry->d_inode;
+
+ list_del(&dentry->d_alias);
+ dentry->d_inode = NULL;
+ iput(inode);
+ }
+ parent = dentry->d_parent;
+ d_free(dentry);
+ dput(parent);
}
-#endif
- inode->i_ddir_count++;
- _get_inode(inode);
- }
-}
-
-static inline blocking void dec_ddir(struct dentry * entry, struct inode * inode)
-{
- if(entry->d_flag & D_INC_DDIR) {
- entry->d_flag &= ~D_INC_DDIR;
- inode->i_ddir_count--;
- if(!inode->i_ddir_count)
- __iput(inode);
}
}
-/* Do not inline this many times. */
-static void d_panic(void)
-{
- panic("VFS: dcache directory corruption");
-}
+#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
-static inline struct ddir * d_dir(struct dentry * entry)
+struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
{
- struct ddir * res = BYTE_SUB(entry, sizeof(struct ddir));
-
- if(!(entry->d_flag & D_DIR))
- d_panic();
-#ifdef DEBUG
- if(!entry)
- panic("entry NULL!");
- if(BASE_DHEADER(res) != BASE_DHEADER(entry))
- printk("Scheisse!!!\n");
-#endif
- return res;
-}
+ char * str;
+ struct dentry *dentry;
-static /*inline*/ struct dheader * dinit(int isdir, int size)
-{
- struct dheader * res = (struct dheader*)__get_free_page(GFP_KERNEL);
- int restlen = PAGE_SIZE - sizeof(struct dheader);
- struct dentry * ptr = BYTE_ADD(res, sizeof(struct dheader));
+ dentry = kmalloc(sizeof(struct dentry), GFP_KERNEL);
+ if (!dentry)
+ return NULL;
- if(!res)
+ str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);
+ if (!str) {
+ kfree(dentry);
return NULL;
- memset(res, 0, sizeof(struct dheader));
- if(isdir) {
- ptr = BYTE_ADD(ptr, sizeof(struct ddir));
- size += sizeof(struct ddir);
}
- if(BASE_DHEADER(ptr) != res)
- panic("Bad kernel page alignment");
- size += sizeof(struct dentry) - D_MAXLEN;
- res->emptylist = NULL;
- res->free = 0;
- while(restlen >= size) {
-#ifdef DEBUG
- ins(ptr);
- if(BASE_DHEADER(ptr) != res)
- panic("Wrong dinit!");
-#endif
- ptr->d_next = res->emptylist;
- res->emptylist = ptr;
- ptr = BYTE_ADD(ptr, size);
- res->free++;
- restlen -= size;
- }
- res->maxfree = res->free;
- return res;
-}
-static /*inline*/ struct dentry * __dalloc(struct anchors * anchor,
- struct dentry * parent, int isdir,
- int len, int size)
-{
- struct dheader ** free = isdir ? &anchor->dir_free : &anchor->free;
- struct dheader ** full = isdir ? &anchor->dir_full : &anchor->full;
- struct dheader * base = *free;
- struct dentry * res;
+ memcpy(str, name->name, name->len);
+ str[name->len] = 0;
- if(!base) {
- base = dinit(isdir, size);
- if(!base)
- return NULL;
- insert_header(free, base);
- }
- base->free--;
- res = base->emptylist;
- if(!(base->emptylist = res->d_next)) {
- remove_header(free, base);
- insert_header(full, base);
- }
- memset(res, 0, sizeof(struct dentry) - D_MAXLEN);
- if(isdir) {
- res->d_flag = D_DIR;
- memset(d_dir(res), 0, sizeof(struct ddir));
- }
- res->d_len = len;
- res->d_parent = parent;
- if(parent) {
- struct ddir * pdir = d_dir(parent);
-#ifdef DEBUG
- if(pdir->dd_alloced > 1 && !IS_ROOT(parent)) {
- printpath(parent);
- printk(" dd_alloced=%d\n", pdir->dd_alloced);
- }
-#endif
- pdir->dd_alloced++;
- }
-#ifdef DEBUG
- x_alloc++;
-#endif
- return res;
+ dentry->d_count = 0;
+ dentry->d_flags = 0;
+ dentry->d_inode = NULL;
+ dentry->d_parent = parent;
+ dentry->d_mounts = dentry;
+ dentry->d_covers = dentry;
+ INIT_LIST_HEAD(&dentry->d_hash);
+ INIT_LIST_HEAD(&dentry->d_alias);
+ INIT_LIST_HEAD(&dentry->d_lru);
+
+ dentry->d_name.name = str;
+ dentry->d_name.len = name->len;
+ dentry->d_name.hash = name->hash;
+ dentry->d_revalidate = NULL;
+ return dentry;
}
-struct dentry * d_alloc(struct dentry * parent, int len, int isdir)
+/*
+ * Fill in inode information in the entry.
+ *
+ * This turns negative dentries into productive full members
+ * of society.
+ *
+ * NOTE! This assumes that the inode count has been incremented
+ * (or otherwise set) by the caller to indicate that it is now
+ * in use by the dcache..
+ */
+void d_instantiate(struct dentry *entry, struct inode * inode)
{
- int i, size;
+ if (inode)
+ list_add(&entry->d_alias, &inode->i_dentry);
-#ifdef DEBUG
- if(the_root)
- recursive_test(the_root);
- LOG("d_alloc", parent);
-#endif
- if(len >= D_MEDIUM) {
- if(len >= D_LARGE) {
- i = 3;
- size = D_HUGE;
- } else {
- i = 2;
- size = D_LARGE;
- }
- } else if(len >= D_SMALL) {
- i = 1;
- size = D_MEDIUM;
- } else {
- i = 0;
- size = D_SMALL;
- }
- return __dalloc(&anchors[i], parent, isdir, len, size);
+ entry->d_inode = inode;
}
-extern blocking struct dentry * d_alloc_root(struct inode * root_inode)
+struct dentry * d_alloc_root(struct inode * root_inode, struct dentry *old_root)
{
- struct dentry * res = the_root;
-
- if(res) {
- d_del(res, D_NO_CLEAR_INODE); /* invalidate everything beyond */
- } else {
- struct ddir * ddir;
+ struct dentry *res = NULL;
- the_root = res = d_alloc(NULL, 0, 1);
- LOG("d_alloc_root", res);
+ if (root_inode) {
+ res = d_alloc(NULL, &(const struct qstr) { "/", 1, 0 });
res->d_parent = res;
- res->d_name[0]='\0';
- ddir = d_dir(res);
- ddir->dd_alloced = 999; /* protect from deletion */
+ res->d_count = 1;
+ d_instantiate(res, root_inode);
}
- insert_alias(&root_inode->i_dentry, res);
- root_inode->i_dent_count++;
- root_inode->i_ddir_count++;
- res->u.d_inode = root_inode;
return res;
}
-static inline unsigned long d_hash(char first, char last)
+static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)
{
- return ((unsigned long)first ^ ((unsigned long)last << 4)) & (D_HASHSIZE-1);
+ hash += (unsigned long) parent;
+ hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
+ return dentry_hashtable + (hash & D_HASHMASK);
}
-static inline struct dentry ** d_base_entry(struct ddir * pdir, struct dentry * entry)
+static inline struct dentry * __dlookup(struct list_head *head, struct dentry * parent, struct qstr * name)
{
- return &pdir->dd_hashtable[d_hash(entry->d_name[0],
- entry->d_name[entry->d_len-1])];
-}
+ struct list_head *tmp = head->next;
+ int len = name->len;
+ int hash = name->hash;
+ const unsigned char *str = name->name;
-static inline struct dentry ** d_base_qstr(struct ddir * pdir,
- struct qstr * s1,
- struct qstr * s2)
-{
- unsigned long hash;
+ while (tmp != head) {
+ struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
- if(s2 && s2->len) {
- hash = d_hash(s1->name[0], s2->name[s2->len-1]);
- } else {
- hash = d_hash(s1->name[0], s1->name[s1->len-1]);
+ tmp = tmp->next;
+ if (dentry->d_name.hash != hash)
+ continue;
+ if (dentry->d_name.len != len)
+ continue;
+ if (dentry->d_parent != parent)
+ continue;
+ if (memcmp(dentry->d_name.name, str, len))
+ continue;
+ return dentry;
}
- return &pdir->dd_hashtable[hash];
-}
-
-
-static /*inline*/ blocking void _d_remove_from_parent(struct dentry * entry,
- struct ddir * pdir,
- struct inode * inode,
- int flags)
-{
- if(entry->d_flag & D_HASHED) {
- struct dentry ** base = d_base_entry(pdir, entry);
-
- remove_hash(base, entry);
- entry->d_flag &= ~D_HASHED;
- pdir->dd_hashed--;
- if(!(entry->d_flag & D_PRELIMINARY)) {
- pdir->dd_true_hashed--;
- if(!inode) {
-#ifdef DEBUG
- if(!entry->d_next || !entry->d_prev) {
- printpath(entry);
- printk(" flags=%x d_flag=%x negs=%d "
- "hashed=%d\n", flags, entry->d_flag,
- pdir->dd_negs, pdir->dd_hashed);
- }
-#endif
- remove_alias(&pdir->dd_neglist, entry);
- pdir->dd_negs--;
- }
- }
- } else if(!(entry->d_flag & D_ZOMBIE)) {
-#ifdef DEBUG
- if(!pdir->dd_alloced) printk("dd_alloced is 0!\n");
-#endif
- pdir->dd_alloced--;
- }
- if(entry->d_flag & D_BASKET) {
- remove_basket(&pdir->dd_basketlist, entry);
- entry->d_flag &= ~D_BASKET;
- }
-}
-
-/* Theoretically, zombies should never or extremely seldom appear,
- * so this code is nearly superfluous.
- * A way to get zombies is while using inodes (i_count>0), unlink()
- * them as well as rmdir() the parent dir => the parent dir becomes a zombie.
- * Zombies are *not* in the hashtable, because somebody could re-creat()
- * that filename in it's parent dir again.
- * Besides coding errors during beta phase, when forcing an umount()
- * (e.g. at shutdown time), inodes could be in use such that the parent
- * dir is cleared, resulting also in zombies.
- */
-static /*inline*/ void _d_handle_zombie(struct dentry * entry,
- struct ddir * ddir,
- struct ddir * pdir)
-{
- if(entry->d_flag & D_DIR) {
- if(entry->d_flag & D_ZOMBIE) {
- if(!has_sons(ddir)) {
- entry->d_flag &= ~D_ZOMBIE;
- remove_hash(&pdir->dd_zombielist, entry);
- if(!pdir->dd_zombielist &&
- (entry->d_parent->d_flag & D_ZOMBIE)) {
- d_del(entry->d_parent, D_NORMAL);
- }
- }
- } else if(has_sons(ddir)) {
- entry->d_flag |= D_ZOMBIE;
- insert_hash(&pdir->dd_zombielist, entry);
-
- /* This condition is no longer a bug, with the removal
- * of recursive_clear() this happens naturally during
- * an unmount attempt of a filesystem which is busy.
- */
-#if 0
- /* Not sure when this message should show up... */
- if(!IS_ROOT(entry)) {
- printk("VFS: clearing dcache directory "
- "with successors\n");
-#ifdef DEBUG
- printpath(entry);
- printk(" d_flag=%x alloced=%d negs=%d hashed=%d "
- "basket=%p zombies=%p\n",
- entry->d_flag, ddir->dd_alloced,
- ddir->dd_negs, ddir->dd_hashed,
- ddir->dd_basketlist, ddir->dd_zombielist);
-#endif
- }
-#endif
- }
- }
-}
-
-static /*inline*/ blocking void _d_del(struct dentry * entry,
- struct anchors * anchor,
- int flags)
-{
- struct dheader ** free;
- struct dheader ** full;
- struct dheader * base = BASE_DHEADER(entry);
- struct ddir * ddir = NULL;
- struct ddir * pdir;
- struct inode * inode = entry->d_flag & D_PRELIMINARY ? NULL : entry->u.d_inode;
-
-#ifdef DEBUG
- if(inode)
- xcheck("_d_del", inode);
-#endif
- if(!entry->d_parent) {
- printk("VFS: dcache parent is NULL\n");
- return;
- }
- if(entry->d_flag & D_DIR) {
- free = &anchor->dir_free;
- full = &anchor->dir_full;
- } else {
- free = &anchor->free;
- full = &anchor->full;
- }
- pdir = d_dir(entry->d_parent);
- if(!IS_ROOT(entry))
- _d_remove_from_parent(entry, pdir, inode, flags);
-
- /* This may block, be careful! _d_remove_from_parent() is
- * thus called before.
- */
- if(entry->d_flag & D_DIR)
- ddir = d_dir(entry);
- if(IS_ROOT(entry))
- return;
-
- if(flags & D_NO_FREE) {
- /* Make it re-d_add()able */
- pdir->dd_alloced++;
- entry->d_flag &= D_DIR;
- } else
- _d_handle_zombie(entry, ddir, pdir);
-
- /* This dec_ddir() must occur after zombie handling. */
- if(!has_true_sons(pdir))
- dec_ddir(entry->d_parent, entry->d_parent->u.d_inode);
-
- entry->u.d_inode = NULL;
- if(inode) {
- remove_alias(&inode->i_dentry, entry);
- inode->i_dent_count--;
- if (entry->d_flag & D_DIR)
- dec_ddir(entry, inode);
-
- if(!(flags & D_NO_CLEAR_INODE) &&
- !(atomic_read(&inode->i_count) +
- inode->i_ddir_count +
- inode->i_dent_count)) {
-#ifdef DEBUG
- printk("#");
-#endif
- /* This may block also. */
- _clear_inode(inode, 0, 0);
- }
- }
- if(!(flags & D_NO_FREE) && !(entry->d_flag & D_ZOMBIE)) {
- base->free++;
- if(base->free == base->maxfree) {
-#ifndef DEBUG
- remove_header(free, base);
- free_page((unsigned long)base);
- goto done;
-#endif
- }
- entry->d_next = base->emptylist;
- base->emptylist = entry;
- if(!entry->d_next) {
- remove_header(full, base);
- insert_header(free, base);
- }
-#ifdef DEBUG
- x_freed++;
-#endif
- }
-#ifndef DEBUG
-done:
-#else
- x_free++;
-#endif
+ return NULL;
}
-blocking void d_del(struct dentry * entry, int flags)
+struct dentry * d_lookup(struct dentry * dir, struct qstr * name)
{
- int i;
-
- if(!entry)
- return;
- LOG("d_clear", entry);
- if(entry->d_len >= D_MEDIUM) {
- if(entry->d_len >= D_LARGE) {
- i = 3;
- } else {
- i = 2;
- }
- } else if(entry->d_len >= D_SMALL) {
- i = 1;
- } else {
- i = 0;
- }
- _d_del(entry, &anchors[i], flags);
+ return __dlookup(d_hash(dir, name->hash), dir, name);
}
-static inline struct dentry * __dlookup(struct dentry ** base,
- struct qstr * name,
- struct qstr * appendix)
+static inline void d_insert_to_parent(struct dentry * entry, struct dentry * parent)
{
- struct dentry * tmp = *base;
-
- if(tmp && name->len) {
- int totallen = name->len;
-
- if(appendix)
- totallen += appendix->len;
- do {
- if(tmp->d_len == totallen &&
- !(tmp->d_flag & D_DUPLICATE) &&
- !strncmp(tmp->d_name, name->name, name->len) &&
- (!appendix || !strncmp(tmp->d_name+name->len,
- appendix->name, appendix->len)))
- return tmp;
- tmp = tmp->d_hash_next;
- } while(tmp != *base);
- }
- return NULL;
+ list_add(&entry->d_hash, d_hash(dget(parent), entry->d_name.hash));
}
-struct dentry * d_lookup(struct inode * dir,
- struct qstr * name,
- struct qstr * appendix)
+static inline void d_remove_from_parent(struct dentry * dentry, struct dentry * parent)
{
- if(dir->i_dentry) {
- struct ddir * ddir = d_dir(dir->i_dentry);
- struct dentry ** base = d_base_qstr(ddir, name, appendix);
-
- return __dlookup(base, name, appendix);
- }
- return NULL;
+ list_del(&dentry->d_hash);
+ dput(parent);
}
-static /*inline*/ blocking void _d_insert_to_parent(struct dentry * entry,
- struct ddir * pdir,
- struct inode * inode,
- struct qstr * ininame,
- int flags)
-{
- struct dentry ** base;
- struct dentry * parent = entry->d_parent;
-#ifdef DEBUG
- if(!pdir->dd_alloced)
- printk("dd_alloced is 0!\n");
-#endif
- base = d_base_qstr(pdir, ininame, NULL);
- if(!(flags & (D_NOCHECKDUP|D_DUPLICATE)) &&
- __dlookup(base, ininame, NULL)) {
- d_del(entry, D_NO_CLEAR_INODE);
- return;
- }
- if(entry->d_flag & D_HASHED) {
- printk("VFS: dcache entry is already hashed\n");
- return;
- }
- if(!(flags & D_PRELIMINARY))
- pdir->dd_true_hashed++;
- pdir->dd_hashed++;
- insert_hash(base, entry);
- entry->d_flag |= D_HASHED;
- pdir->dd_alloced--;
- if(flags & D_BASKET)
- insert_basket(&pdir->dd_basketlist, entry);
-
-#ifdef DEBUG
- if(inode && inode->i_dentry && (entry->d_flag & D_DIR)) {
- struct dentry * tmp = inode->i_dentry;
- printk("Auweia inode=%p entry=%p (%p %p %s)\n",
- inode, entry, parent->u.d_inode, parent, parent->d_name);
- printk("entry path="); printpath(entry); printk("\n");
- do {
- TST("auweia",tmp);
- printk("alias path="); printpath(tmp); printk("\n");
- tmp = tmp->d_next;
- } while(tmp != inode->i_dentry);
- printk("\n");
- }
-#endif
- if(has_true_sons(pdir))
- inc_ddir(parent, parent->u.d_inode);
- if(!inode && !(flags & D_PRELIMINARY)) {
- insert_alias(&pdir->dd_neglist, entry);
- pdir->dd_negs++;
-
- /* Don't allow the negative list to grow too much ... */
- while(pdir->dd_negs > (pdir->dd_true_hashed >> 1) + 5)
- d_del(pdir->dd_neglist->d_prev, D_REMOVE);
- }
-}
-
-blocking void d_add(struct dentry * entry, struct inode * inode,
- struct qstr * ininame, int flags)
+/*
+ * When a file is deleted, we have two options:
+ * - turn this dentry into a negative dentry
+ * - unhash this dentry and free it.
+ *
+ * Usually, we want to just turn this into
+ * a negative dentry, but if anybody else is
+ * currently using the dentry or the inode
+ * we can't do that and we fall back on removing
+ * it from the hash queues and waiting for
+ * it to be deleted later when it has no users
+ */
+void d_delete(struct dentry * dentry)
{
- struct dentry * parent = entry->d_parent;
- struct qstr dummy;
- struct ddir * pdir;
+ /*
+ * Are we the only user?
+ */
+ if (dentry->d_count == 1) {
+ struct inode * inode = dentry->d_inode;
-#ifdef DEBUG
- if(inode)
- xcheck("d_add", inode);
- if(IS_ROOT(entry)) {
- printk("VFS: d_add for root dentry ");
- printpath(entry);
- printk(" -> ");
- if(ininame)
- printk("%s", ininame->name);
- printk("\n");
+ dentry->d_inode = NULL;
+ list_del(&dentry->d_alias);
+ iput(inode);
return;
}
- if(!parent)
- panic("d_add with parent==NULL");
- LOG("d_add", entry);
-#endif
- if(ininame) {
- if(ininame->len != entry->d_len) {
- printk("VFS: d_add with wrong string length");
- entry->d_len = ininame->len; /* kludge */
- }
- memcpy(entry->d_name, ininame->name, ininame->len);
- entry->d_name[ininame->len] = '\0';
- } else {
- dummy.name = entry->d_name;
- dummy.len = entry->d_len;
- ininame = &dummy;
- }
- if(entry->d_flag & D_HASHED)
- printk("VFS: d_add of already added dcache entry\n");
- pdir = d_dir(parent);
- _d_insert_to_parent(entry, pdir, inode, ininame, flags);
- entry->d_flag |= flags;
- if(inode && !(flags & D_PRELIMINARY)) {
- if(entry->d_flag & D_DIR) {
- if(inode->i_dentry) {
- printk("VFS: creating dcache directory alias\n");
- return;
- }
- }
- insert_alias(&inode->i_dentry, entry);
- inode->i_dent_count++;
- }
- entry->u.d_inode = inode;
+ /*
+ * If not, just drop the dentry and let dput
+ * pick up the tab..
+ */
+ d_drop(dentry);
}
-blocking struct dentry * d_entry(struct dentry * parent,
- struct qstr * name,
- struct inode * inode)
+void d_add(struct dentry * entry, struct inode * inode)
{
- struct ddir * pdir = d_dir(parent);
- struct dentry ** base = d_base_qstr(pdir, name, NULL);
- struct dentry * found = __dlookup(base, name, NULL);
-
- if(!found) {
- int isdir = (inode && S_ISDIR(inode->i_mode));
-
- found = d_alloc(parent, name->len, isdir);
- if(found) {
- d_add(found, inode, name,
- isdir ? (D_DIR|D_NOCHECKDUP) : D_NOCHECKDUP);
- } else
- printk("VFS: problem with d_alloc\n");
- }
- return found;
+ d_insert_to_parent(entry, entry->d_parent);
+ d_instantiate(entry, inode);
}
-blocking void d_entry_preliminary(struct dentry * parent,
- struct qstr * name,
- unsigned long ino)
+static inline void alloc_new_name(struct dentry * entry, struct qstr *newname)
{
- struct ddir * pdir = d_dir(parent);
- struct dentry ** base = d_base_qstr(pdir, name, NULL);
- struct dentry * found = __dlookup(base, name, NULL);
+ int len = newname->len;
+ int hash = newname->hash;
+ char *name = (char *) entry->d_name.name;
- if(!found && ino) {
- struct dentry * new = d_alloc(parent, name->len, 0);
-
- if(new) {
- d_add(new, NULL, name, D_PRELIMINARY|D_NOCHECKDUP);
- new->u.d_ino = ino;
- } else
- printk("VFS: problem with d_alloc\n");
+ if (NAME_ALLOC_LEN(len) != NAME_ALLOC_LEN(entry->d_name.len)) {
+ name = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL);
+ if (!name)
+ printk("out of memory for dcache\n");
+ kfree(entry->d_name.name);
+ entry->d_name.name = name;
}
+ memcpy(name, newname->name, len);
+ name[len] = 0;
+ entry->d_name.len = len;
+ entry->d_name.hash = hash;
}
-blocking void d_move(struct dentry * entry, struct inode * newdir,
- struct qstr * newname, struct qstr * newapp)
+void d_move(struct dentry * dentry, struct dentry * newdir, struct qstr * newname)
{
- struct ddir tmp;
- struct dentry * new;
- struct inode * inode;
- int len;
- int flags;
-
- if(!entry)
+ if (!dentry)
return;
- inode = entry->u.d_inode;
- flags = entry->d_flag;
- if((flags & D_PRELIMINARY) || !inode) {
- if(!(flags & D_PRELIMINARY))
- printk("VFS: trying to move negative dcache entry\n");
- d_del(entry, D_NO_CLEAR_INODE);
- return;
- }
-#if 0
-printk("d_move %p '%s' -> '%s%s' dent_count=%d\n", inode, entry->d_name,
- newname->name, newapp ? newapp->name : "", inode->i_dent_count);
-#endif
- if(flags & D_ZOMBIE) {
- printk("VFS: moving zombie entry\n");
- }
- if(flags & D_DIR) {
- struct ddir * ddir = d_dir(entry);
-
- memcpy(&tmp, ddir, sizeof(struct ddir));
- /* Simulate empty dir for d_del(). */
- memset(ddir, 0, sizeof(struct ddir));
- }
- len = newname->len;
- if(newapp) {
- len += newapp->len;
- flags |= D_BASKET;
- } else
- flags &= ~D_BASKET;
- new = d_alloc(newdir->i_dentry, len, flags & D_DIR);
- memcpy(new->d_name, newname->name, newname->len);
- if(newapp)
- memcpy(new->d_name+newname->len, newapp->name, newapp->len);
- new->d_name[len] = '\0';
- d_del(entry, D_NO_CLEAR_INODE);
- d_add(new, inode, NULL, flags & (D_DIR|D_BASKET));
- if(flags & D_DIR) {
- struct ddir * ddir = d_dir(new);
+ if (!dentry->d_inode)
+ printk("VFS: moving negative dcache entry\n");
- memcpy(ddir, &tmp, sizeof(struct ddir));
- }
+ d_remove_from_parent(dentry, dentry->d_parent);
+ alloc_new_name(dentry, newname);
+ dentry->d_parent = newdir;
+ d_insert_to_parent(dentry, newdir);
}
-int d_path(struct dentry * entry, struct inode * chroot, char * buf)
+int d_path(struct dentry * entry, struct dentry * chroot, char * buf)
{
- if(IS_ROOT(entry) || (chroot && entry->u.d_inode == chroot &&
- !(entry->d_flag & D_PRELIMINARY))) {
+ if (IS_ROOT(entry) || (chroot && entry == chroot)) {
*buf = '/';
return 1;
} else {
int len = d_path(entry->d_parent, chroot, buf);
buf += len;
- if(len > 1) {
+ if (len > 1) {
*buf++ = '/';
len++;
}
- memcpy(buf, entry->d_name, entry->d_len);
- return len + entry->d_len;
+ memcpy(buf, entry->d_name.name, entry->d_name.len);
+ return len + entry->d_name.len;
}
}
-struct dentry * d_basket(struct dentry * dir_entry)
+void dcache_init(void)
{
- if(dir_entry && (dir_entry->d_flag & D_DIR)) {
- struct ddir * ddir = d_dir(dir_entry);
-
- return ddir->dd_basketlist;
- } else
- return NULL;
-}
-
-int d_isbasket(struct dentry * entry)
-{
- return entry->d_flag & D_BASKET;
-}
-
-blocking struct inode * d_inode(struct dentry ** changing_entry)
-{
- struct dentry * entry = *changing_entry;
- struct inode * inode;
-
-#ifdef CONFIG_DCACHE_PRELOAD
- if(entry->d_flag & D_PRELIMINARY) {
- struct qstr name = { entry->d_name, entry->d_len };
- struct ddir * pdir = d_dir(entry->d_parent);
- struct dentry ** base = d_base_qstr(pdir, &name, NULL);
- struct dentry * found;
- unsigned long ino;
- struct inode * dir = entry->d_parent->u.d_inode;
- TST("d_inode",entry);
- ino = entry->u.d_ino;
- if(!dir)
- d_panic();
-
- /* Prevent concurrent d_lookup()s or d_inode()s before
- * giving up vfs_lock. This just removes from the parent,
- * but does not deallocate it.
- */
-
- /* !!!!!!! Aiee, here is an unresolved race if somebody
- * unlink()s the inode during the iget(). The problem is
- * that we need to synchronize externally. Proposed solution:
- * put a rw_lock (read-mode) on the parent dir for each
- * iget(), lookup() and so on, and a write-mode lock for
- * everything that changes the dir (e.g. unlink()), and do
- * this consistently everywhere in the generic VFS (not in
- * the concrete filesystems). This should kill similar
- * races everywhere, with a single clean concept.
- * Later, the synchronization stuff can be cleaned out
- * of the concrete fs'es.
- */
- d_del(entry, D_NO_CLEAR_INODE|D_NO_FREE);
- vfs_unlock();
-
- /* This circumvents the normal lookup() of pathnames.
- * Therefore, preliminary entries must not be used
- * (see FS_NO_DCACHE and FS_NO_PRELIM) if the fs does not
- * permit fetching *valid* inodes with plain iget().
- */
- inode = __iget(dir->i_sb, ino, 0);
- vfs_lock();
- if(!inode) {
- printk("VFS: preliminary dcache entry was invalid\n");
- *changing_entry = NULL;
- return NULL;
- }
- xcheck("d_inode iget()", inode);
- if((found = __dlookup(base, &name, NULL))) {
- d_del(entry, D_NO_CLEAR_INODE);
- *changing_entry = found;
- } else if(S_ISDIR(inode->i_mode)) {
- struct dentry * new = d_alloc(entry->d_parent, entry->d_len, 1);
- if(new)
- d_add(new, inode, &name, D_DIR);
- *changing_entry = new;
-
- /* Finally deallocate old entry. */
- d_del(entry, D_NO_CLEAR_INODE);
- } else {
- /* Re-insert to the parent, but now as normal dentry. */
- d_add(entry, inode, NULL, 0);
- }
- return inode;
- }
-#endif
- inode = entry->u.d_inode;
- if(inode) {
-#ifdef DEBUG
- xcheck("d_inode", inode);
-#endif
- iinc_zero(inode);
- }
- return inode;
+ int i;
+ struct list_head *d = dentry_hashtable;
+
+ i = D_HASHSIZE;
+ do {
+ INIT_LIST_HEAD(d);
+ d++;
+ i--;
+ } while (i);
}
diff --git a/fs/devices.c b/fs/devices.c
index d3b1d6846..26f668e7f 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -209,9 +209,7 @@ int check_disk_change(kdev_t dev)
printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
kdevname(dev));
- for (i=0 ; i<NR_SUPER ; i++)
- if (super_blocks[i].s_dev == dev)
- put_super(super_blocks[i].s_dev);
+
invalidate_inodes(dev);
invalidate_buffers(dev);
diff --git a/fs/dquot.c b/fs/dquot.c
index 59d2112d9..b19c939be 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -13,7 +13,7 @@
* diskquota system. This implementation is not based on any BSD
* kernel sourcecode.
*
- * Version: $Id: dquot.c,v 1.11 1997/01/06 06:53:02 davem Exp $
+ * Version: $Id: dquot.c,v 1.2 1997/06/17 13:25:58 ralf Exp $
*
* Author: Marco van Wieringen <mvw@mcs.ow.nl> <mvw@tnix.net>
*
@@ -227,7 +227,7 @@ static void write_dquot(struct dquot *dquot)
lock_dquot(dquot);
down(&dquot->dq_mnt->mnt_sem);
if (filp->f_op->llseek) {
- if (filp->f_op->llseek(filp->f_inode, filp,
+ if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
up(&dquot->dq_mnt->mnt_sem);
unlock_dquot(dquot);
@@ -238,10 +238,9 @@ static void write_dquot(struct dquot *dquot)
fs = get_fs();
set_fs(KERNEL_DS);
- if (filp->f_op->write(filp->f_inode, filp,
+ if (filp->f_op->write(filp->f_dentry->d_inode, filp,
(char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
dquot->dq_flags &= ~DQ_MOD;
- /* inode->i_status |= ST_MODIFIED is willingly *not* done here */
up(&dquot->dq_mnt->mnt_sem);
set_fs(fs);
@@ -260,7 +259,7 @@ static void read_dquot(struct dquot *dquot)
lock_dquot(dquot);
down(&dquot->dq_mnt->mnt_sem);
if (filp->f_op->llseek) {
- if (filp->f_op->llseek(filp->f_inode, filp,
+ if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
up(&dquot->dq_mnt->mnt_sem);
unlock_dquot(dquot);
@@ -270,7 +269,7 @@ static void read_dquot(struct dquot *dquot)
filp->f_pos = dqoff(dquot->dq_id);
fs = get_fs();
set_fs(KERNEL_DS);
- filp->f_op->read(filp->f_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
+ filp->f_op->read(filp->f_dentry->d_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
up(&dquot->dq_mnt->mnt_sem);
set_fs(fs);
if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
@@ -947,39 +946,53 @@ int quota_off(kdev_t dev, short type)
int quota_on(kdev_t dev, short type, char *path)
{
- struct file *filp = (struct file *)NULL;
+ struct file *filp = NULL;
+ struct dentry *dentry;
struct vfsmount *vfsmnt;
struct inode *inode;
struct dquot *dquot;
char *tmp;
int error;
- if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL)
- return(-ENODEV);
- if (vfsmnt->mnt_quotas[type] != (struct file *)NULL)
- return(-EBUSY);
- if ((error = getname(path, &tmp)) != 0)
- return(error);
- error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+ vfsmnt = lookup_vfsmnt(dev);
+ if (vfsmnt == NULL)
+ return -ENODEV;
+
+ if (vfsmnt->mnt_quotas[type] != NULL)
+ return -EBUSY;
+
+ tmp = getname(path);
+ error = PTR_ERR(tmp);
+ if (IS_ERR(tmp))
+ return error;
+
+ dentry = open_namei(tmp, O_RDWR, 0600);
putname(tmp);
- if (error)
- return(error);
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ return error;
+ inode = dentry->d_inode;
+
if (!S_ISREG(inode->i_mode)) {
- iput(inode);
- return(-EACCES);
+ dput(dentry);
+ return -EACCES;
}
- if ((filp = get_empty_filp()) != (struct file *)NULL) {
+
+ filp = get_empty_filp();
+ if (filp != NULL) {
filp->f_mode = (O_RDWR + 1) & O_ACCMODE;
filp->f_flags = O_RDWR;
- filp->f_inode = inode;
+ 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) {
- if ((error = get_write_access(inode)) == 0) {
+ error = get_write_access(inode);
+ if (!error) {
if (filp->f_op && filp->f_op->open)
error = filp->f_op->open(inode, filp);
- if (error == 0) {
+ if (!error) {
vfsmnt->mnt_quotas[type] = filp;
dquot = dqget(dev, 0, type);
vfsmnt->mnt_iexp[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
@@ -987,7 +1000,7 @@ int quota_on(kdev_t dev, short type, char *path)
dqput(dquot);
vfsmnt->mnt_sb->dq_op = &dquot_operations;
add_dquot_ref(dev, type);
- return(0);
+ return 0;
}
put_write_access(inode);
}
@@ -996,8 +1009,8 @@ int quota_on(kdev_t dev, short type, char *path)
put_filp(filp);
} else
error = -EMFILE;
- iput(inode);
- return(error);
+ dput(dentry);
+ return error;
}
/*
@@ -1009,7 +1022,6 @@ int quota_on(kdev_t dev, short type, char *path)
asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
{
int cmds = 0, type = 0, flags = 0;
- struct inode *ino;
kdev_t dev;
int ret = -EINVAL;
@@ -1035,19 +1047,22 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
}
ret = -EINVAL;
- if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS))
- dev = 0;
- else {
- int error = namei(NAM_FOLLOW_LINK, special, &ino);
- if(error)
+ dev = 0;
+ if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) {
+ mode_t mode;
+ struct dentry * dentry;
+
+ dentry = namei(special);
+ if (IS_ERR(dentry))
goto out;
- dev = ino->i_rdev;
+
+ dev = dentry->d_inode->i_rdev;
+ mode = dentry->d_inode->i_mode;
+ dput(dentry);
+
ret = -ENOTBLK;
- if (!S_ISBLK(ino->i_mode)) {
- iput(ino);
+ if (!S_ISBLK(mode))
goto out;
- }
- iput(ino);
}
ret = -EINVAL;
diff --git a/fs/exec.c b/fs/exec.c
index 74d228019..6facaf283 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -88,6 +88,10 @@ __initfunc(void binfmt_setup(void))
init_aout_binfmt();
#endif
+#ifdef CONFIG_BINFMT_AOUT32
+ init_aout32_binfmt();
+#endif
+
#ifdef CONFIG_BINFMT_JAVA
init_java_binfmt();
#endif
@@ -134,22 +138,24 @@ int unregister_binfmt(struct linux_binfmt * fmt)
}
#endif /* CONFIG_MODULES */
-int open_inode(struct inode * inode, int mode)
+int open_dentry(struct dentry * dentry, int mode)
{
int fd;
+ struct inode * inode = dentry->d_inode;
if (!inode->i_op || !inode->i_op->default_file_ops)
return -EINVAL;
fd = get_unused_fd();
if (fd >= 0) {
struct file * f = get_empty_filp();
+
if (!f) {
put_unused_fd(fd);
return -ENFILE;
}
f->f_flags = mode;
f->f_mode = (mode+1) & O_ACCMODE;
- f->f_inode = inode;
+ f->f_dentry = dentry;
f->f_pos = 0;
f->f_reada = 0;
f->f_op = inode->i_op->default_file_ops;
@@ -162,7 +168,7 @@ int open_inode(struct inode * inode, int mode)
}
}
current->files->fd[fd] = f;
- atomic_inc(&inode->i_count);
+ dget(dentry);
}
return fd;
}
@@ -186,7 +192,7 @@ asmlinkage int sys_uselib(const char * library)
goto out;
file = current->files->fd[fd];
retval = -ENOEXEC;
- if (file && file->f_inode && file->f_op && file->f_op->read) {
+ if (file && file->f_dentry && file->f_op && file->f_op->read) {
for (fmt = formats ; fmt ; fmt = fmt->next) {
int (*fn)(int) = fmt->load_shlib;
if (!fn)
@@ -320,7 +326,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm)
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_ops = NULL;
mpnt->vm_offset = 0;
- mpnt->vm_inode = NULL;
+ mpnt->vm_dentry = NULL;
mpnt->vm_pte = 0;
insert_vm_struct(current->mm, mpnt);
current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
@@ -341,25 +347,18 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm)
* that aren't on a block boundary, and for files on filesystems
* without bmap support.
*/
-int read_exec(struct inode *inode, unsigned long offset,
+int read_exec(struct dentry *dentry, unsigned long offset,
char * addr, unsigned long count, int to_kmem)
{
struct file file;
+ struct inode * inode = dentry->d_inode;
int result = -ENOEXEC;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto end_readexec;
- file.f_mode = 1;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_inode = inode;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto end_readexec;
- if (!file.f_op || !file.f_op->read)
+ if (init_private_file(&file, dentry, 1))
+ goto end_readexec;
+ if (!file.f_op->read)
goto close_readexec;
if (file.f_op->llseek) {
if (file.f_op->llseek(inode,&file,offset,0) != offset)
@@ -481,7 +480,7 @@ void flush_old_exec(struct linux_binprm * bprm)
flush_thread();
if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
- permission(bprm->inode,MAY_READ))
+ permission(bprm->dentry->d_inode,MAY_READ))
current->dumpable = 0;
flush_old_signals(current->sig);
@@ -496,20 +495,21 @@ int prepare_binprm(struct linux_binprm *bprm)
{
int mode;
int retval,id_change;
+ struct inode * inode = bprm->dentry->d_inode;
- mode = bprm->inode->i_mode;
+ mode = inode->i_mode;
if (!S_ISREG(mode)) /* must be regular file */
return -EACCES;
if (!(mode & 0111)) /* with at least _one_ execute bit set */
return -EACCES;
- if (IS_NOEXEC(bprm->inode)) /* FS mustn't be mounted noexec */
+ if (IS_NOEXEC(inode)) /* FS mustn't be mounted noexec */
return -EACCES;
- if (!bprm->inode->i_sb)
+ if (!inode->i_sb)
return -EACCES;
- if ((retval = permission(bprm->inode, MAY_EXEC)) != 0)
+ if ((retval = permission(inode, MAY_EXEC)) != 0)
return retval;
/* better not execute files which are being written to */
- if (bprm->inode->i_writecount > 0)
+ if (inode->i_writecount > 0)
return -ETXTBSY;
bprm->e_uid = current->euid;
@@ -518,7 +518,7 @@ int prepare_binprm(struct linux_binprm *bprm)
/* Set-uid? */
if (mode & S_ISUID) {
- bprm->e_uid = bprm->inode->i_uid;
+ bprm->e_uid = inode->i_uid;
if (bprm->e_uid != current->euid)
id_change = 1;
}
@@ -530,7 +530,7 @@ int prepare_binprm(struct linux_binprm *bprm)
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
- bprm->e_gid = bprm->inode->i_gid;
+ bprm->e_gid = inode->i_gid;
if (!in_group_p(bprm->e_gid))
id_change = 1;
}
@@ -539,7 +539,7 @@ int prepare_binprm(struct linux_binprm *bprm)
/* We can't suid-execute if we're sharing parts of the executable */
/* or if we're being traced (or if suid execs are not allowed) */
/* (current->mm->count > 1 is ok, as we'll get a new mm anyway) */
- if (IS_NOSUID(bprm->inode)
+ if (IS_NOSUID(inode)
|| (current->flags & PF_PTRACED)
|| (current->fs->count > 1)
|| (atomic_read(&current->sig->count) > 1)
@@ -550,7 +550,7 @@ int prepare_binprm(struct linux_binprm *bprm)
}
memset(bprm->buf,0,sizeof(bprm->buf));
- return read_exec(bprm->inode,0,bprm->buf,128,1);
+ return read_exec(bprm->dentry,0,bprm->buf,128,1);
}
void remove_arg_zero(struct linux_binprm *bprm)
@@ -585,16 +585,19 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
(eh->fh.f_flags & 0x3000) == 0x3000)
{
char * dynloader[] = { "/sbin/loader" };
- iput(bprm->inode);
- bprm->dont_iput = 1;
+ struct dentry * dentry;
+
+ dput(bprm->dentry);
+ bprm->dentry = NULL;
remove_arg_zero(bprm);
bprm->p = copy_strings(1, dynloader, bprm->page, bprm->p, 2);
bprm->argc++;
bprm->loader = bprm->p;
- retval = open_namei(dynloader[0], 0, 0, &bprm->inode, NULL);
- if (retval)
+ dentry = open_namei(dynloader[0], 0, 0);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
return retval;
- bprm->dont_iput = 0;
+ bprm->dentry = dentry;
retval = prepare_binprm(bprm);
if (retval<0)
return retval;
@@ -610,15 +613,15 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
continue;
retval = fn(bprm, regs);
if (retval >= 0) {
- if(!bprm->dont_iput)
- iput(bprm->inode);
- bprm->dont_iput=1;
+ if (bprm->dentry)
+ dput(bprm->dentry);
+ bprm->dentry = NULL;
current->did_exec = 1;
return retval;
}
if (retval != -ENOEXEC)
break;
- if (bprm->dont_iput) /* We don't have the inode anymore*/
+ if (!bprm->dentry) /* We don't have the dentry anymore */
return retval;
}
if (retval != -ENOEXEC) {
@@ -647,29 +650,38 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
{
struct linux_binprm bprm;
+ struct dentry * dentry;
int retval;
int i;
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
bprm.page[i] = 0;
- retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
- if (retval)
+
+ dentry = open_namei(filename, 0, 0);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
return retval;
+
+ bprm.dentry = dentry;
bprm.filename = filename;
bprm.sh_bang = 0;
bprm.java = 0;
bprm.loader = 0;
bprm.exec = 0;
- bprm.dont_iput = 0;
- if ((bprm.argc = count(argv)) < 0)
+ if ((bprm.argc = count(argv)) < 0) {
+ dput(dentry);
return bprm.argc;
- if ((bprm.envc = count(envp)) < 0)
+ }
+
+ if ((bprm.envc = count(envp)) < 0) {
+ dput(dentry);
return bprm.envc;
+ }
retval = prepare_binprm(&bprm);
- if(retval>=0) {
+ if (retval >= 0) {
bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
bprm.exec = bprm.p;
bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0);
@@ -678,16 +690,18 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
retval = -E2BIG;
}
- if(retval>=0)
+ if (retval >= 0)
retval = search_binary_handler(&bprm,regs);
- if(retval>=0)
+ if (retval >= 0)
/* execve success */
return retval;
/* Something went wrong, return the inode and free the argument pages*/
- if(!bprm.dont_iput)
- iput(bprm.inode);
+ if (bprm.dentry)
+ dput(bprm.dentry);
+
for (i=0 ; i<MAX_ARG_PAGES ; i++)
free_page(bprm.page[i]);
- return(retval);
+
+ return retval;
}
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 4d2b561ee..7e159e7d2 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -291,7 +291,7 @@ int ext2_new_block (const struct inode * inode, unsigned long goal,
printk ("ext2_new_block: nonexistent device");
return 0;
}
-retry:
+
lock_super (sb);
es = sb->u.ext2_sb.s_es;
if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) &&
@@ -299,8 +299,6 @@ retry:
(sb->u.ext2_sb.s_resgid == 0 ||
!in_group_p (sb->u.ext2_sb.s_resgid)))) {
unlock_super (sb);
- if(sb->s_ibasket && free_ibasket(sb))
- goto retry;
return 0;
}
@@ -392,8 +390,6 @@ repeat:
}
if (k >= sb->u.ext2_sb.s_groups_count) {
unlock_super (sb);
- if(sb->s_ibasket && free_ibasket(sb))
- goto retry;
return 0;
}
bitmap_nr = load_block_bitmap (sb, i);
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index d9b1957e3..b75acdef5 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -65,6 +65,7 @@ struct inode_operations ext2_dir_inode_operations = {
ext2_mknod, /* mknod */
ext2_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -211,9 +212,6 @@ revalidate:
offset = 0;
brelse (bh);
}
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
+ UPDATE_ATIME(inode);
return 0;
}
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 1627f5cee..d632133f1 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -72,6 +72,7 @@ struct inode_operations ext2_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
ext2_bmap, /* bmap */
@@ -121,7 +122,7 @@ static inline void remove_suid(struct inode *inode)
mode &= inode->i_mode;
if (mode && !suser()) {
inode->i_mode &= ~mode;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
}
@@ -250,7 +251,7 @@ static long ext2_file_write (struct inode * inode, struct file * filp,
inode->u.ext2_i.i_osync--;
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
filp->f_pos = pos;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return written;
}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index a486679f9..bc16722e4 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -154,8 +154,26 @@ static int load_inode_bitmap (struct super_block * sb,
return 0;
}
+/*
+ * NOTE! When we get the inode, we're the only people
+ * that have access to it, and as such there are no
+ * race conditions we have to worry about. The inode
+ * is not on the hash-lists, and it cannot be reached
+ * through the filesystem because the directory entry
+ * has been deleted earlier.
+ *
+ * HOWEVER: we must make sure that we get no aliases,
+ * which means that we have to call "clear_inode()"
+ * _before_ we mark the inode not in use in the inode
+ * bitmaps. Otherwise a newly created file might use
+ * the same inode number (not actually the same pointer
+ * though), and then we'd have two inodes sharing the
+ * same inode number and space on the harddisk.
+ */
void ext2_free_inode (struct inode * inode)
{
+ int is_directory;
+ unsigned long ino;
struct super_block * sb;
struct buffer_head * bh;
struct buffer_head * bh2;
@@ -171,9 +189,8 @@ void ext2_free_inode (struct inode * inode)
printk ("ext2_free_inode: inode has no device\n");
return;
}
- if (atomic_read(&inode->i_count) > 1) {
- printk ("ext2_free_inode: inode has count=%d\n",
- atomic_read(&inode->i_count));
+ if (inode->i_count > 1) {
+ printk ("ext2_free_inode: inode has count=%d\n", inode->i_count);
return;
}
if (inode->i_nlink) {
@@ -186,47 +203,53 @@ void ext2_free_inode (struct inode * inode)
return;
}
- ext2_debug ("freeing inode %lu\n", inode->i_ino);
+ ino = inode->i_ino;
+ ext2_debug ("freeing inode %lu\n", ino);
sb = inode->i_sb;
lock_super (sb);
- if (inode->i_ino < EXT2_FIRST_INO(sb) ||
- inode->i_ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) {
+ if (ino < EXT2_FIRST_INO(sb) ||
+ ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) {
ext2_error (sb, "free_inode",
"reserved inode or nonexistent inode");
unlock_super (sb);
return;
}
es = sb->u.ext2_sb.s_es;
- block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb);
- bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb);
+ block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
+ bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb);
bitmap_nr = load_inode_bitmap (sb, block_group);
bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
+
+ is_directory = S_ISDIR(inode->i_mode);
+
+ /* Do this BEFORE marking the inode not in use */
+ if (sb->dq_op)
+ sb->dq_op->free_inode (inode, 1);
+ clear_inode (inode);
+
+ /* Ok, now we can actually update the inode bitmaps.. */
if (!ext2_clear_bit (bit, bh->b_data))
ext2_warning (sb, "ext2_free_inode",
- "bit already cleared for inode %lu", inode->i_ino);
+ "bit already cleared for inode %lu", ino);
else {
gdp = get_group_desc (sb, block_group, &bh2);
gdp->bg_free_inodes_count =
cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1);
- if (S_ISDIR(inode->i_mode))
+ if (is_directory)
gdp->bg_used_dirs_count =
cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
mark_buffer_dirty(bh2, 1);
es->s_free_inodes_count =
cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
- inode->i_dirt = 0;
}
mark_buffer_dirty(bh, 1);
if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- if (sb->dq_op)
- sb->dq_op->free_inode (inode, 1);
sb->s_dirt = 1;
- clear_inode (inode);
unlock_super (sb);
}
@@ -240,7 +263,7 @@ static void inc_inode_version (struct inode * inode,
int mode)
{
inode->u.ext2_i.i_version++;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return;
}
@@ -404,7 +427,6 @@ repeat:
sb->s_dirt = 1;
inode->i_mode = mode;
inode->i_sb = sb;
- atomic_set(&inode->i_count, 1);
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
@@ -416,7 +438,7 @@ repeat:
mode |= S_ISGID;
} else
inode->i_gid = current->fsgid;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
inode->i_ino = j;
inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = 0;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index f2dbff2d1..0fa14cfe1 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -31,14 +31,24 @@
static int ext2_update_inode(struct inode * inode, int do_sync);
+/*
+ * Called at each iput()
+ */
void ext2_put_inode (struct inode * inode)
{
ext2_discard_prealloc (inode);
- if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO ||
+}
+
+/*
+ * Called at the last iput() if i_nlink is zero.
+ */
+void ext2_delete_inode (struct inode * inode)
+{
+ if (inode->i_ino == EXT2_ACL_IDX_INO ||
inode->i_ino == EXT2_ACL_DATA_INO)
return;
inode->u.ext2_i.i_dtime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_update_inode(inode, IS_SYNC(inode));
inode->i_size = 0;
if (inode->i_blocks)
@@ -248,7 +258,7 @@ repeat:
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
ext2_sync_inode (inode);
else
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return result;
}
@@ -322,7 +332,7 @@ repeat:
}
inode->i_ctime = CURRENT_TIME;
inode->i_blocks += blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
inode->u.ext2_i.i_next_alloc_block = new_block;
inode->u.ext2_i.i_next_alloc_goal = tmp;
brelse (bh);
@@ -591,7 +601,6 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
else for (block = 0; block < EXT2_N_BLOCKS; block++)
raw_inode->i_block[block] = cpu_to_le32(inode->u.ext2_i.i_data[block]);
mark_buffer_dirty(bh, 1);
- inode->i_dirt = 0;
if (do_sync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -671,7 +680,7 @@ int ext2_notify_change(struct inode *inode, struct iattr *iattr)
inode->i_flags &= ~S_IMMUTABLE;
inode->u.ext2_i.i_flags &= ~EXT2_IMMUTABLE_FL;
}
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return 0;
}
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 387600bbf..c0514c01e 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -62,7 +62,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
else
inode->i_flags &= ~MS_NOATIME;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return 0;
case EXT2_IOC_GETVERSION:
return put_user(inode->u.ext2_i.i_version, (int *) arg);
@@ -74,7 +74,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
if (get_user(inode->u.ext2_i.i_version, (int *) arg))
return -EFAULT;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return 0;
default:
return -ENOTTY;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 421393581..2a7c42bff 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -27,6 +27,7 @@
#include <linux/string.h>
#include <linux/locks.h>
+
/*
* define how far ahead to read directories while searching them.
*/
@@ -154,36 +155,26 @@ failure:
return NULL;
}
-int ext2_lookup (struct inode * dir, const char * name, int len,
- struct inode ** result)
+int ext2_lookup(struct inode * dir, struct dentry *dentry)
{
- unsigned long ino;
+ struct inode * inode;
struct ext2_dir_entry * de;
struct buffer_head * bh;
- *result = NULL;
- if (!dir)
- return -ENOENT;
- if (!S_ISDIR(dir->i_mode)) {
- iput (dir);
- return -ENOTDIR;
- }
- if (len > EXT2_NAME_LEN) {
- iput (dir);
+ if (dentry->d_name.len > EXT2_NAME_LEN)
return -ENAMETOOLONG;
+
+ bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ inode = NULL;
+ if (bh) {
+ unsigned long ino = le32_to_cpu(de->inode);
+ brelse (bh);
+ inode = iget(dir->i_sb, ino);
+
+ if (!inode)
+ return -EACCES;
}
- ino = dir->i_version;
- if (!(bh = ext2_find_entry (dir, name, len, &de))) {
- iput (dir);
- return -ENOENT;
- }
- ino = le32_to_cpu(de->inode);
- brelse (bh);
- if (!(*result = iget (dir->i_sb, ino))) {
- iput (dir);
- return -EACCES;
- }
- iput (dir);
+ d_add(dentry, inode);
return 0;
}
@@ -256,7 +247,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
de->inode = le32_to_cpu(0);
de->rec_len = le16_to_cpu(sb->s_blocksize);
dir->i_size = offset + sb->s_blocksize;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
} else {
ext2_debug ("skipping to next block\n");
@@ -301,7 +292,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
* and/or different from the directory change time.
*/
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
*res_dir = de;
@@ -347,31 +338,35 @@ static int ext2_delete_entry (struct ext2_dir_entry * dir,
return -ENOENT;
}
-int ext2_create (struct inode * dir,const char * name, int len, int mode,
- struct inode ** result)
+/*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+ * is so far negative - it has no inode.
+ *
+ * If the create succeeds, we fill in the inode information
+ * with d_instantiate().
+ */
+int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
struct buffer_head * bh;
struct ext2_dir_entry * de;
int err;
- *result = NULL;
if (!dir)
return -ENOENT;
inode = ext2_new_inode (dir, mode, &err);
- if (!inode) {
- iput (dir);
+ if (!inode)
return err;
- }
+
inode->i_op = &ext2_file_inode_operations;
inode->i_mode = mode;
- inode->i_dirt = 1;
- bh = ext2_add_entry (dir, name, len, &de, &err);
+ mark_inode_dirty(inode);
+ bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
if (!bh) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
- iput (dir);
return err;
}
de->inode = cpu_to_le32(inode->i_ino);
@@ -382,13 +377,11 @@ int ext2_create (struct inode * dir,const char * name, int len, int mode,
wait_on_buffer (bh);
}
brelse (bh);
- iput (dir);
- *result = inode;
+ d_instantiate(dentry, inode);
return 0;
}
-int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
- int rdev)
+int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
struct inode * inode;
struct buffer_head * bh;
@@ -398,21 +391,13 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
if (!dir)
return -ENOENT;
- if (len > EXT2_NAME_LEN) {
- iput (dir);
+ if (dentry->d_name.len > EXT2_NAME_LEN)
return -ENAMETOOLONG;
- }
- bh = ext2_find_entry (dir, name, len, &de);
- if (bh) {
- brelse (bh);
- iput (dir);
- return -EEXIST;
- }
+
inode = ext2_new_inode (dir, mode, &err);
- if (!inode) {
- iput (dir);
+ if (!inode)
return err;
- }
+
inode->i_uid = current->fsuid;
inode->i_mode = mode;
inode->i_op = NULL;
@@ -433,13 +418,12 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
init_fifo(inode);
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = to_kdev_t(rdev);
- inode->i_dirt = 1;
- bh = ext2_add_entry (dir, name, len, &de, &err);
+ mark_inode_dirty(inode);
+ bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
if (!bh) {
inode->i_nlink--;
- inode->i_dirt = 1;
- iput (inode);
- iput (dir);
+ mark_inode_dirty(inode);
+ iput(inode);
return err;
}
de->inode = cpu_to_le32(inode->i_ino);
@@ -449,47 +433,34 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- brelse (bh);
- iput (dir);
- iput (inode);
+ brelse(bh);
+ d_instantiate(dentry, inode);
return 0;
}
-int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
+int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
struct buffer_head * bh, * dir_block;
struct ext2_dir_entry * de;
int err;
- if (!dir)
- return -ENOENT;
- if (len > EXT2_NAME_LEN) {
- iput (dir);
+ if (dentry->d_name.len > EXT2_NAME_LEN)
return -ENAMETOOLONG;
- }
- bh = ext2_find_entry (dir, name, len, &de);
- if (bh) {
- brelse (bh);
- iput (dir);
- return -EEXIST;
- }
- if (dir->i_nlink >= EXT2_LINK_MAX) {
- iput (dir);
+
+ if (dir->i_nlink >= EXT2_LINK_MAX)
return -EMLINK;
- }
+
inode = ext2_new_inode (dir, S_IFDIR, &err);
- if (!inode) {
- iput (dir);
+ if (!inode)
return err;
- }
+
inode->i_op = &ext2_dir_inode_operations;
inode->i_size = inode->i_sb->s_blocksize;
dir_block = ext2_bread (inode, 0, 1, &err);
if (!dir_block) {
- iput (dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
return err;
}
@@ -510,12 +481,11 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
- inode->i_dirt = 1;
- bh = ext2_add_entry (dir, name, len, &de, &err);
+ mark_inode_dirty(inode);
+ bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
if (!bh) {
- iput (dir);
inode->i_nlink = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
return err;
}
@@ -527,9 +497,8 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
wait_on_buffer (bh);
}
dir->i_nlink++;
- dir->i_dirt = 1;
- iput (dir);
- iput (inode);
+ mark_inode_dirty(dir);
+ d_instantiate(dentry, inode);
brelse (bh);
return 0;
}
@@ -593,58 +562,53 @@ static int empty_dir (struct inode * inode)
return 1;
}
-int ext2_rmdir (struct inode * dir, const char * name, int len)
+int ext2_rmdir (struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
struct buffer_head * bh;
struct ext2_dir_entry * de;
-repeat:
if (!dir)
return -ENOENT;
inode = NULL;
- if (len > EXT2_NAME_LEN) {
- iput (dir);
+ if (dentry->d_name.len > EXT2_NAME_LEN)
return -ENAMETOOLONG;
- }
- bh = ext2_find_entry (dir, name, len, &de);
+
+ bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
retval = -ENOENT;
if (!bh)
goto end_rmdir;
retval = -EPERM;
- if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode))))
- goto end_rmdir;
+ inode = dentry->d_inode;
+
if (inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize (inode, -1);
- if (inode->i_dev != dir->i_dev) {
- retval = -EBUSY;
- goto end_rmdir;
- }
- if (le32_to_cpu(de->inode) != inode->i_ino) {
- iput(inode);
- brelse(bh);
- current->counter = 0;
- schedule();
- goto repeat;
- }
+
if ((dir->i_mode & S_ISVTX) && !fsuser() &&
current->fsuid != inode->i_uid &&
current->fsuid != dir->i_uid)
goto end_rmdir;
if (inode == dir) /* we may not delete ".", but "../dir" is ok */
goto end_rmdir;
- if (!S_ISDIR(inode->i_mode)) {
- retval = -ENOTDIR;
+
+ retval = -ENOTDIR;
+ if (!S_ISDIR(inode->i_mode))
goto end_rmdir;
- }
+
+ retval = -EIO;
+ if (inode->i_dev != dir->i_dev)
+ goto end_rmdir;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ goto end_rmdir;
+
down(&inode->i_sem);
if (!empty_dir (inode))
retval = -ENOTEMPTY;
else if (le32_to_cpu(de->inode) != inode->i_ino)
retval = -ENOENT;
else {
- if (atomic_read(&inode->i_count) > 1) {
+ if (inode->i_count > 1) {
/*
* Are we deleting the last instance of a busy directory?
* Better clean up if so.
@@ -671,56 +635,51 @@ repeat:
(int) inode->i_nlink);
inode->i_version = ++event;
inode->i_nlink = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
+ d_delete(dentry);
+
end_rmdir:
- iput (dir);
- iput (inode);
brelse (bh);
return retval;
}
-int ext2_unlink (struct inode * dir, const char * name, int len)
+int ext2_unlink(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
struct buffer_head * bh;
struct ext2_dir_entry * de;
-repeat:
- if (!dir)
- return -ENOENT;
retval = -ENOENT;
inode = NULL;
- if (len > EXT2_NAME_LEN) {
- iput (dir);
+ if (dentry->d_name.len > EXT2_NAME_LEN)
return -ENAMETOOLONG;
- }
- bh = ext2_find_entry (dir, name, len, &de);
+
+ bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
if (!bh)
goto end_unlink;
- if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode))))
- goto end_unlink;
+
+ inode = dentry->d_inode;
if (inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize (inode, -1);
+
retval = -EPERM;
if (S_ISDIR(inode->i_mode))
goto end_unlink;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
goto end_unlink;
- if (le32_to_cpu(de->inode) != inode->i_ino) {
- iput(inode);
- brelse(bh);
- current->counter = 0;
- schedule();
- goto repeat;
- }
if ((dir->i_mode & S_ISVTX) && !fsuser() &&
current->fsuid != inode->i_uid &&
current->fsuid != dir->i_uid)
goto end_unlink;
+
+ retval = -EIO;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ goto end_unlink;
+
if (!inode->i_nlink) {
ext2_warning (inode->i_sb, "ext2_unlink",
"Deleting nonexistent file (%lu), %d",
@@ -737,20 +696,19 @@ repeat:
wait_on_buffer (bh);
}
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime;
retval = 0;
+ d_delete(dentry); /* This also frees the inode */
+
end_unlink:
brelse (bh);
- iput (inode);
- iput (dir);
return retval;
}
-int ext2_symlink (struct inode * dir, const char * name, int len,
- const char * symname)
+int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
{
struct ext2_dir_entry * de;
struct inode * inode = NULL;
@@ -761,7 +719,6 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
char c;
if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) {
- iput (dir);
return err;
}
inode->i_mode = S_IFLNK | S_IRWXUGO;
@@ -775,9 +732,8 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
name_block = ext2_bread (inode, 0, 1, &err);
if (!name_block) {
- iput (dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
return err;
}
@@ -797,23 +753,13 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
brelse (name_block);
}
inode->i_size = i;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
- bh = ext2_find_entry (dir, name, len, &de);
- if (bh) {
- inode->i_nlink--;
- inode->i_dirt = 1;
- iput (inode);
- brelse (bh);
- iput (dir);
- return -EEXIST;
- }
- bh = ext2_add_entry (dir, name, len, &de, &err);
+ bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
if (!bh) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
- iput (dir);
return err;
}
de->inode = cpu_to_le32(inode->i_ino);
@@ -824,47 +770,30 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
wait_on_buffer (bh);
}
brelse (bh);
- iput (dir);
- iput (inode);
+ d_instantiate(dentry, inode);
return 0;
}
-int ext2_link (struct inode * oldinode, struct inode * dir,
- const char * name, int len)
+int ext2_link (struct inode * inode, struct inode * dir, struct dentry *dentry)
{
struct ext2_dir_entry * de;
struct buffer_head * bh;
int err;
- if (S_ISDIR(oldinode->i_mode)) {
- iput (oldinode);
- iput (dir);
+ if (S_ISDIR(inode->i_mode))
return -EPERM;
- }
- if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
- iput (oldinode);
- iput (dir);
+
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return -EPERM;
- }
- if (oldinode->i_nlink >= EXT2_LINK_MAX) {
- iput (oldinode);
- iput (dir);
+
+ if (inode->i_nlink >= EXT2_LINK_MAX)
return -EMLINK;
- }
- bh = ext2_find_entry (dir, name, len, &de);
- if (bh) {
- brelse (bh);
- iput (dir);
- iput (oldinode);
- return -EEXIST;
- }
- bh = ext2_add_entry (dir, name, len, &de, &err);
- if (!bh) {
- iput (dir);
- iput (oldinode);
+
+ bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!bh)
return err;
- }
- de->inode = cpu_to_le32(oldinode->i_ino);
+
+ de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
@@ -872,35 +801,33 @@ int ext2_link (struct inode * oldinode, struct inode * dir,
wait_on_buffer (bh);
}
brelse (bh);
- iput (dir);
- oldinode->i_nlink++;
- oldinode->i_ctime = CURRENT_TIME;
- oldinode->i_dirt = 1;
- iput (oldinode);
+ inode->i_nlink++;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ inode->i_count++;
+ d_instantiate(dentry, inode);
return 0;
}
-static int subdir (struct inode * new_inode, struct inode * old_inode)
+/*
+ * Trivially implemented using the dcache structure
+ */
+static int subdir (struct dentry * new_dentry, struct dentry * old_dentry)
{
- int ino;
int result;
- atomic_inc(&new_inode->i_count);
result = 0;
for (;;) {
- if (new_inode == old_inode) {
- result = 1;
- break;
+ if (new_dentry != old_dentry) {
+ struct dentry * parent = new_dentry->d_parent;
+ if (parent == new_dentry)
+ break;
+ new_dentry = parent;
+ continue;
}
- if (new_inode->i_dev != old_inode->i_dev)
- break;
- ino = new_inode->i_ino;
- if (ext2_lookup (new_inode, "..", 2, &new_inode))
- break;
- if (new_inode->i_ino == ino)
- break;
+ result = 1;
+ break;
}
- iput (new_inode);
return result;
}
@@ -908,10 +835,6 @@ static int subdir (struct inode * new_inode, struct inode * old_inode)
((struct ext2_dir_entry *) ((char *) buffer + \
le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->inode
-#define PARENT_NAME(buffer) \
- ((struct ext2_dir_entry *) ((char *) buffer + \
- le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->name
-
/*
* rename uses retrying to avoid race-conditions: at least they should be
* minimal.
@@ -923,43 +846,27 @@ static int subdir (struct inode * new_inode, struct inode * old_inode)
* 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, const char * old_name,
- int old_len, struct inode * new_dir,
- const char * new_name, int new_len)
+static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
+ struct inode * new_dir,struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
struct ext2_dir_entry * old_de, * new_de;
int retval;
- goto start_up;
-try_again:
- if (new_bh && new_de) {
- ext2_delete_entry(new_de, new_bh);
- new_dir->i_version = ++event;
- }
- brelse (old_bh);
- brelse (new_bh);
- brelse (dir_bh);
- iput (old_inode);
- iput (new_inode);
- current->counter = 0;
- schedule ();
-start_up:
old_inode = new_inode = NULL;
old_bh = new_bh = dir_bh = NULL;
new_de = NULL;
retval = -ENAMETOOLONG;
- if (old_len > EXT2_NAME_LEN)
+ if (old_dentry->d_name.len > EXT2_NAME_LEN)
goto end_rename;
- old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de);
+ old_bh = ext2_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
retval = -ENOENT;
if (!old_bh)
goto end_rename;
- old_inode = __iget (old_dir->i_sb, le32_to_cpu(old_de->inode), 0); /* don't cross mnt-points */
- if (!old_inode)
- goto end_rename;
+ old_inode = old_dentry->d_inode;
+
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
@@ -967,9 +874,10 @@ start_up:
goto end_rename;
if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode))
goto end_rename;
- new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de);
+
+ new_inode = new_dentry->d_inode;
+ new_bh = ext2_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de);
if (new_bh) {
- new_inode = __iget (new_dir->i_sb, le32_to_cpu(new_de->inode), 0); /* no mntp cross */
if (!new_inode) {
brelse (new_bh);
new_bh = NULL;
@@ -987,13 +895,13 @@ start_up:
if (!S_ISDIR(old_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir (new_dir, old_inode))
+ if (subdir(new_dentry, old_dentry))
goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir (new_inode))
goto end_rename;
retval = -EBUSY;
- if (atomic_read(&new_inode->i_count) > 1)
+ if (new_inode->i_count > 1)
goto end_rename;
}
retval = -EPERM;
@@ -1006,7 +914,7 @@ start_up:
if (new_inode && !S_ISDIR(new_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir (new_dir, old_inode))
+ if (subdir(new_dentry, old_dentry))
goto end_rename;
dir_bh = ext2_bread (old_inode, 0, 0, &retval);
if (!dir_bh)
@@ -1018,48 +926,37 @@ start_up:
goto end_rename;
}
if (!new_bh)
- new_bh = ext2_add_entry (new_dir, new_name, new_len, &new_de,
+ new_bh = ext2_add_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de,
&retval);
if (!new_bh)
goto end_rename;
new_dir->i_version = ++event;
- /*
- * sanity checking before doing the rename - avoid races
- */
- if (new_inode && (le32_to_cpu(new_de->inode) != new_inode->i_ino))
- goto try_again;
- if (le32_to_cpu(new_de->inode) && !new_inode)
- goto try_again;
- if (le32_to_cpu(old_de->inode) != old_inode->i_ino)
- goto try_again;
+
/*
* ok, that's it
*/
new_de->inode = le32_to_cpu(old_inode->i_ino);
- retval = ext2_delete_entry (old_de, old_bh);
- if (retval == -ENOENT)
- goto try_again;
- if (retval)
- goto end_rename;
+ ext2_delete_entry (old_de, old_bh);
+
old_dir->i_version = ++event;
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
}
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
- old_dir->i_dirt = 1;
+ mark_inode_dirty(old_dir);
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
mark_buffer_dirty(dir_bh, 1);
old_dir->i_nlink--;
- old_dir->i_dirt = 1;
+ mark_inode_dirty(old_dir);
if (new_inode) {
new_inode->i_nlink--;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
} else {
new_dir->i_nlink++;
- new_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
}
}
mark_buffer_dirty(old_bh, 1);
@@ -1072,15 +969,15 @@ start_up:
ll_rw_block (WRITE, 1, &new_bh);
wait_on_buffer (new_bh);
}
+
+ /* Update the dcache */
+ d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
+ d_delete(new_dentry);
retval = 0;
end_rename:
brelse (dir_bh);
brelse (old_bh);
brelse (new_bh);
- iput (old_inode);
- iput (new_inode);
- iput (old_dir);
- iput (new_dir);
return retval;
}
@@ -1097,16 +994,15 @@ end_rename:
* 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, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len)
+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_name, old_len, new_dir,
- new_name, new_len);
+ 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 635a45692..1adc82185 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -133,9 +133,10 @@ void ext2_put_super (struct super_block * sb)
static struct super_operations ext2_sops = {
ext2_read_inode,
- NULL,
ext2_write_inode,
ext2_put_inode,
+ ext2_delete_inode,
+ NULL,
ext2_put_super,
ext2_write_super,
ext2_statfs,
@@ -632,7 +633,8 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
*/
sb->s_dev = dev;
sb->s_op = &ext2_sops;
- if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO))) {
+ sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO), NULL);
+ if (!sb->s_root) {
sb->s_dev = 0;
for (i = 0; i < db_count; i++)
if (sb->u.ext2_sb.s_group_desc[i])
@@ -761,7 +763,7 @@ void cleanup_module(void)
#endif
-void ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
+int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
{
unsigned long overhead;
unsigned long overhead_per_group;
@@ -792,5 +794,5 @@ void ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
tmp.f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
tmp.f_ffree = ext2_count_free_inodes (sb);
tmp.f_namelen = EXT2_NAME_LEN;
- copy_to_user(buf, &tmp, bufsiz);
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 4d5a5cada..781f9165d 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -25,6 +25,7 @@
#include <linux/stat.h>
static int ext2_readlink (struct inode *, char *, int);
+static struct dentry *ext2_follow_link(struct inode *, struct dentry *);
/*
* symlinks can't do much...
@@ -41,6 +42,7 @@ struct inode_operations ext2_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
ext2_readlink, /* readlink */
+ ext2_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -49,37 +51,54 @@ struct inode_operations ext2_symlink_inode_operations = {
NULL /* smap */
};
+static struct dentry * ext2_follow_link(struct inode * inode, struct dentry *base)
+{
+ int error;
+ struct buffer_head * bh = NULL;
+ char * link;
+
+ link = (char *) inode->u.ext2_i.i_data;
+ if (inode->i_blocks) {
+ if (!(bh = ext2_bread (inode, 0, 0, &error))) {
+ dput(base);
+ return ERR_PTR(-EIO);
+ }
+ link = bh->b_data;
+ }
+ UPDATE_ATIME(inode);
+ base = lookup_dentry(link, base, 1);
+ if (bh)
+ brelse(bh);
+ return base;
+}
+
static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh = NULL;
char * link;
- int i, err;
+ int i;
if (buflen > inode->i_sb->s_blocksize - 1)
buflen = inode->i_sb->s_blocksize - 1;
+
+ link = (char *) inode->u.ext2_i.i_data;
if (inode->i_blocks) {
+ int err;
bh = ext2_bread (inode, 0, 0, &err);
if (!bh) {
- iput (inode);
if(err < 0) /* indicate type of error */
return err;
return 0;
}
link = bh->b_data;
}
- else
- link = (char *) inode->u.ext2_i.i_data;
i = 0;
while (i < buflen && link[i])
i++;
if (copy_to_user(buffer, link, i))
i = -EFAULT;
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
- iput (inode);
+ UPDATE_ATIME(inode);
if (bh)
brelse (bh);
return i;
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index a9e59ca00..5933ff77c 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -91,7 +91,7 @@ repeat:
}
*p = 0;
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
bforget(bh);
if (free_count == 0) {
block_to_free = tmp;
@@ -110,7 +110,8 @@ repeat:
return retry;
}
-static int trunc_indirect (struct inode * inode, int offset, u32 * p)
+static int trunc_indirect (struct inode * inode, int offset, u32 * p,
+ int in_inode)
{
int i, tmp;
struct buffer_head * bh;
@@ -124,103 +125,16 @@ static int trunc_indirect (struct inode * inode, int offset, u32 * p)
#define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
int indirect_block = INDIRECT_BLOCK;
- tmp = *p;
+ tmp = in_inode ? *p : le32_to_cpu(*p);
if (!tmp)
return 0;
ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (tmp != *p) {
- brelse (ind_bh);
- return 1;
- }
- if (!ind_bh) {
- *p = 0;
- return 0;
- }
-repeat:
- for (i = indirect_block ; i < addr_per_block ; i++) {
- if (i < 0)
- i = 0;
- if (i < indirect_block)
- goto repeat;
- ind = i + (u32 *) ind_bh->b_data;
- tmp = le32_to_cpu(*ind);
- if (!tmp)
- continue;
- bh = get_hash_table (inode->i_dev, tmp,
- inode->i_sb->s_blocksize);
- if (i < indirect_block) {
- brelse (bh);
- goto repeat;
- }
- if ((bh && bh->b_count != 1) || tmp != le32_to_cpu(*ind)) {
- retry = 1;
- brelse (bh);
- continue;
- }
- *ind = cpu_to_le32(0);
- mark_buffer_dirty(ind_bh, 1);
- bforget(bh);
- if (free_count == 0) {
- block_to_free = tmp;
- free_count++;
- } else if (free_count > 0 && block_to_free == tmp - free_count)
- free_count++;
- else {
- ext2_free_blocks (inode, block_to_free, free_count);
- block_to_free = tmp;
- free_count = 1;
- }
-/* ext2_free_blocks (inode, tmp, 1); */
- inode->i_blocks -= blocks;
- inode->i_dirt = 1;
- }
- if (free_count > 0)
- ext2_free_blocks (inode, block_to_free, free_count);
- ind = (u32 *) ind_bh->b_data;
- for (i = 0; i < addr_per_block; i++)
- if (le32_to_cpu(*(ind++)))
- break;
- if (i >= addr_per_block)
- if (ind_bh->b_count != 1)
- retry = 1;
- else {
- tmp = *p;
- *p = 0;
- inode->i_blocks -= blocks;
- inode->i_dirt = 1;
- ext2_free_blocks (inode, tmp, 1);
- }
- if (IS_SYNC(inode) && buffer_dirty(ind_bh)) {
- ll_rw_block (WRITE, 1, &ind_bh);
- wait_on_buffer (ind_bh);
- }
- brelse (ind_bh);
- return retry;
-}
-
-static int trunc_indirect_swab32 (struct inode * inode, int offset, u32 * p)
-{
- int i, tmp;
- struct buffer_head * bh;
- struct buffer_head * ind_bh;
- u32 * ind;
- unsigned long block_to_free = 0;
- unsigned long free_count = 0;
- int retry = 0;
- int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int blocks = inode->i_sb->s_blocksize / 512;
- int indirect_block = INDIRECT_BLOCK;
-
- tmp = le32_to_cpu(*p);
- if (!tmp)
- return 0;
- ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (tmp != le32_to_cpu(*p)) {
+ if (tmp != (in_inode ? *p : le32_to_cpu(*p))) {
brelse (ind_bh);
return 1;
}
if (!ind_bh) {
- *p = cpu_to_le32(0);
+ *p = in_inode ? 0 : cpu_to_le32(0);
return 0;
}
repeat:
@@ -259,7 +173,7 @@ repeat:
}
/* ext2_free_blocks (inode, tmp, 1); */
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
if (free_count > 0)
ext2_free_blocks (inode, block_to_free, free_count);
@@ -271,13 +185,15 @@ repeat:
if (ind_bh->b_count != 1)
retry = 1;
else {
- tmp = le32_to_cpu(*p);
- *p = cpu_to_le32(0);
+ tmp = in_inode ? *p : le32_to_cpu(*p);
+ *p = in_inode ? 0 : cpu_to_le32(0);
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_free_blocks (inode, tmp, 1);
+ bforget(ind_bh);
+ ind_bh = NULL;
}
- if (IS_SYNC(inode) && buffer_dirty(ind_bh)) {
+ if (IS_SYNC(inode) && ind_bh && buffer_dirty(ind_bh)) {
ll_rw_block (WRITE, 1, &ind_bh);
wait_on_buffer (ind_bh);
}
@@ -286,7 +202,7 @@ repeat:
}
static int trunc_dindirect (struct inode * inode, int offset,
- u32 * p)
+ u32 * p, int in_inode)
{
int i, tmp;
struct buffer_head * dind_bh;
@@ -297,75 +213,16 @@ static int trunc_dindirect (struct inode * inode, int offset,
#define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block)
int dindirect_block = DINDIRECT_BLOCK;
- tmp = *p;
- if (!tmp)
- return 0;
- dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (tmp != *p) {
- brelse (dind_bh);
- return 1;
- }
- if (!dind_bh) {
- *p = 0;
- return 0;
- }
-repeat:
- for (i = dindirect_block ; i < addr_per_block ; i++) {
- if (i < 0)
- i = 0;
- if (i < dindirect_block)
- goto repeat;
- dind = i + (u32 *) dind_bh->b_data;
- tmp = le32_to_cpu(*dind);
- if (!tmp)
- continue;
- retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block),
- dind);
- mark_buffer_dirty(dind_bh, 1);
- }
- dind = (u32 *) dind_bh->b_data;
- for (i = 0; i < addr_per_block; i++)
- if (le32_to_cpu(*(dind++)))
- break;
- if (i >= addr_per_block)
- if (dind_bh->b_count != 1)
- retry = 1;
- else {
- tmp = *p;
- *p = 0;
- inode->i_blocks -= blocks;
- inode->i_dirt = 1;
- ext2_free_blocks (inode, tmp, 1);
- }
- if (IS_SYNC(inode) && buffer_dirty(dind_bh)) {
- ll_rw_block (WRITE, 1, &dind_bh);
- wait_on_buffer (dind_bh);
- }
- brelse (dind_bh);
- return retry;
-}
-
-static int trunc_dindirect_swab32 (struct inode * inode, int offset,
- u32 * p)
-{
- int i, tmp;
- struct buffer_head * dind_bh;
- u32 * dind;
- int retry = 0;
- int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int blocks = inode->i_sb->s_blocksize / 512;
- int dindirect_block = DINDIRECT_BLOCK;
-
- tmp = le32_to_cpu(*p);
+ tmp = in_inode ? *p : le32_to_cpu(*p);
if (!tmp)
return 0;
dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (tmp != le32_to_cpu(*p)) {
+ if (tmp != (in_inode ? *p : le32_to_cpu(*p))) {
brelse (dind_bh);
return 1;
}
if (!dind_bh) {
- *p = cpu_to_le32(0);
+ *p = in_inode ? 0 : cpu_to_le32(0);
return 0;
}
repeat:
@@ -378,8 +235,8 @@ repeat:
tmp = le32_to_cpu(*dind);
if (!tmp)
continue;
- retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block),
- dind);
+ retry |= trunc_indirect(inode, offset + (i * addr_per_block),
+ dind, 0);
mark_buffer_dirty(dind_bh, 1);
}
dind = (u32 *) dind_bh->b_data;
@@ -390,13 +247,15 @@ repeat:
if (dind_bh->b_count != 1)
retry = 1;
else {
- tmp = le32_to_cpu(*p);
- *p = cpu_to_le32(0);
+ tmp = in_inode ? *p : le32_to_cpu(*p);
+ *p = in_inode ? 0 : cpu_to_le32(0);
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_free_blocks (inode, tmp, 1);
+ bforget(dind_bh);
+ dind_bh = 0;
}
- if (IS_SYNC(inode) && buffer_dirty(dind_bh)) {
+ if (IS_SYNC(inode) && dind_bh && buffer_dirty(dind_bh)) {
ll_rw_block (WRITE, 1, &dind_bh);
wait_on_buffer (dind_bh);
}
@@ -436,9 +295,9 @@ repeat:
if (i < tindirect_block)
goto repeat;
tind = i + (u32 *) tind_bh->b_data;
- retry |= trunc_dindirect_swab32(inode, EXT2_NDIR_BLOCKS +
+ retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
addr_per_block + (i + 1) * addr_per_block * addr_per_block,
- tind);
+ tind, 0);
mark_buffer_dirty(tind_bh, 1);
}
tind = (u32 *) tind_bh->b_data;
@@ -452,10 +311,12 @@ repeat:
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_free_blocks (inode, tmp, 1);
+ bforget(tind_bh);
+ tind_bh = 0;
}
- if (IS_SYNC(inode) && buffer_dirty(tind_bh)) {
+ if (IS_SYNC(inode) && tind_bh && buffer_dirty(tind_bh)) {
ll_rw_block (WRITE, 1, &tind_bh);
wait_on_buffer (tind_bh);
}
@@ -479,14 +340,14 @@ void ext2_truncate (struct inode * inode)
while (1) {
retry = trunc_direct(inode);
retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
- (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
+ (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK], 1);
retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
EXT2_ADDR_PER_BLOCK(inode->i_sb),
- (u32 *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
+ (u32 *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK], 1);
retry |= trunc_tindirect (inode);
if (!retry)
break;
- if (IS_SYNC(inode) && inode->i_dirt)
+ if (IS_SYNC(inode) && test_bit(I_DIRTY, &inode->i_state))
ext2_sync_inode (inode);
current->counter = 0;
schedule ();
@@ -510,5 +371,5 @@ void ext2_truncate (struct inode * inode)
}
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 62ff8af1e..6223c1c48 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -280,7 +280,7 @@ int fat_free(struct inode *inode,int skip)
12 ? EOF_FAT12 : EOF_FAT16);
else {
MSDOS_I(inode)->i_start = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
lock_fat(inode->i_sb);
while (nr != -1) {
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 82787075a..ca35cc28f 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -52,6 +52,7 @@ struct inode_operations fat_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
@@ -99,6 +100,7 @@ struct inode_operations fat_file_inode_operations_1024 = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -355,7 +357,7 @@ long fat_file_write(
filp->f_pos += written;
if (filp->f_pos > inode->i_size) {
inode->i_size = filp->f_pos;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
fat_set_uptodate(sb, bh, 1);
fat_mark_buffer_dirty(sb, bh, 0);
@@ -365,7 +367,7 @@ long fat_file_write(
return error;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return buf-start;
}
@@ -379,5 +381,5 @@ void fat_truncate(struct inode *inode)
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;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index cf14856d1..e35722aff 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -196,6 +196,7 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent
int debug,error,fat;
int blksize = 512;
struct fat_mount_options opts;
+ struct inode *root_inode;
MOD_INC_USE_COUNT;
if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
@@ -329,7 +330,10 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent
MSDOS_SB(sb)->fat_lock = 0;
MSDOS_SB(sb)->prev_free = 0;
memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options));
- if (!(sb->s_mounted = iget(sb,MSDOS_ROOT_INO))) {
+
+ root_inode = iget(sb,MSDOS_ROOT_INO);
+ sb->s_root = d_alloc_root(root_inode, NULL);
+ if (!sb->s_root) {
sb->s_dev = 0;
printk("get root inode failed\n");
MOD_DEC_USE_COUNT;
@@ -339,7 +343,7 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent
}
-void fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
+int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
{
int free,nr;
struct statfs tmp;
@@ -362,7 +366,7 @@ void fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
tmp.f_files = 0;
tmp.f_ffree = 0;
tmp.f_namelen = 12;
- copy_to_user(buf, &tmp, bufsiz);
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
@@ -514,10 +518,9 @@ void fat_write_inode(struct inode *inode)
linked->i_blocks = inode->i_blocks;
linked->i_atime = inode->i_atime;
MSDOS_I(linked)->i_attrs = MSDOS_I(inode)->i_attrs;
- linked->i_dirt = 1;
+ mark_inode_dirty(linked);
}
- inode->i_dirt = 0;
if (inode->i_ino == MSDOS_ROOT_INO || !inode->i_nlink) return;
if (!(bh = fat_bread(sb, inode->i_ino >> MSDOS_DPB_BITS))) {
printk("dev = %s, ino = %ld\n",
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index d1e9bc6ca..034f62c1f 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -19,13 +19,14 @@
/* Well-known binary file extensions - of course there are many more */
-static char bin_extensions[] =
- "EXE" "COM" "BIN" "APP" "SYS" "DRV" "OVL" "OVR" "OBJ" "LIB" "DLL" "PIF" /* program code */
- "ARC" "ZIP" "LHA" "LZH" "ZOO" "TAR" "Z " "ARJ" /* common archivers */
- "TZ " "TAZ" "TZP" "TPZ" /* abbreviations of tar.Z and tar.zip */
- "GZ " "TGZ" "DEB" /* .gz, .tar.gz and Debian packages */
- "GIF" "BMP" "TIF" "GL " "JPG" "PCX" /* graphics */
- "TFM" "VF " "GF " "PK " "PXL" "DVI"; /* TeX */
+static char ascii_extensions[] =
+ "TXT" "ME " "HTM" "1ST" "LOG" " " /* text files */
+ "C " "H " "CPP" "LIS" "PAS" "FOR" /* programming languages */
+ "F " "MAK" "INC" "BAS" /* programming languages */
+ "BAT" "SH " /* program code :) */
+ "INI" /* config files */
+ "PBM" "PGM" "DXF" /* graphics */
+ "TEX"; /* TeX */
/*
@@ -39,9 +40,7 @@ void fat_fs_panic(struct super_block *s,const char *msg)
not_ro = !(s->s_flags & MS_RDONLY);
if (not_ro) s->s_flags |= MS_RDONLY;
- printk("Filesystem panic (dev %s, ", kdevname(s->s_dev));
- printk("mounted on %s:%ld)\n %s\n", /* note: kdevname returns & static char[] */
- kdevname(s->s_covered->i_dev), s->s_covered->i_ino, msg);
+ printk("Filesystem panic (dev %s).", kdevname(s->s_dev));
if (not_ro)
printk(" File system has been set read-only\n");
}
@@ -62,9 +61,9 @@ int is_binary(char conversion,char *extension)
case 't':
return 0;
case 'a':
- for (walk = bin_extensions; *walk; walk += 3)
- if (!strncmp(extension,walk,3)) return 1;
- return 0;
+ for (walk = ascii_extensions; *walk; walk += 3)
+ if (!strncmp(extension,walk,3)) return 0;
+ return 1; /* default binary conversion */
default:
printk("Invalid conversion mode - defaulting to "
"binary.\n");
@@ -179,7 +178,7 @@ printk("last = %d\n",last);
if (last) fat_access(sb,last,nr);
else {
MSDOS_I(inode)->i_start = nr;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
#ifdef DEBUG
if (last) printk("next set to %d\n",fat_access(sb,last,-1));
@@ -216,7 +215,7 @@ if (last) printk("next set to %d\n",fat_access(sb,last,-1));
#ifdef DEBUG
printk("size is %d now (%x)\n",inode->i_size,inode);
#endif
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
return 0;
}
diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c
index 6a3515eef..a858cd2cc 100644
--- a/fs/fat/mmap.c
+++ b/fs/fat/mmap.c
@@ -29,7 +29,7 @@ static unsigned long fat_file_mmap_nopage(
unsigned long address,
int error_code)
{
- struct inode * inode = area->vm_inode;
+ struct inode * inode = area->vm_dentry->d_inode;
unsigned long page;
unsigned int clear;
int pos;
@@ -101,11 +101,10 @@ int fat_mmap(struct inode * inode, struct file * file, struct vm_area_struct * v
return -EACCES;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
- vma->vm_inode = inode;
- atomic_inc(&inode->i_count);
+ vma->vm_dentry = dget(file->f_dentry);
vma->vm_ops = &fat_file_mmap;
return 0;
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 6418a5d83..57eef2530 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -67,6 +67,34 @@ asmlinkage int sys_dup(unsigned int fildes)
return ret;
}
+#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)
+
+static int setfl(struct file * filp, unsigned long arg)
+{
+ struct inode * inode = filp->f_dentry->d_inode;
+
+ /*
+ * In the case of an append-only file, O_APPEND
+ * cannot be cleared
+ */
+ if (!(arg & O_APPEND) && IS_APPEND(inode))
+ return -EPERM;
+
+ /* Did FASYNC state change? */
+ if ((arg ^ filp->f_flags) & FASYNC) {
+ if (filp->f_op->fasync)
+ filp->f_op->fasync(inode, filp, (arg & FASYNC) != 0);
+ }
+
+ /* required for strict SunOS emulation */
+ if (O_NONBLOCK != O_NDELAY)
+ if (arg & O_NDELAY)
+ arg |= O_NONBLOCK;
+
+ filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
+ return 0;
+}
+
asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
@@ -95,28 +123,7 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
err = filp->f_flags;
break;
case F_SETFL:
- /*
- * In the case of an append-only file, O_APPEND
- * cannot be cleared
- */
- err = -EPERM;
- if (IS_APPEND(filp->f_inode) && !(arg & O_APPEND))
- break;
- err = 0;
- if ((arg & FASYNC) && !(filp->f_flags & FASYNC) &&
- filp->f_op->fasync)
- filp->f_op->fasync(filp->f_inode, filp, 1);
- if (!(arg & FASYNC) && (filp->f_flags & FASYNC) &&
- filp->f_op->fasync)
- filp->f_op->fasync(filp->f_inode, filp, 0);
- /* required for strict SunOS emulation */
- if (O_NONBLOCK != O_NDELAY)
- if (arg & O_NDELAY)
- arg |= O_NONBLOCK;
- filp->f_flags &= ~(O_APPEND | O_NONBLOCK |
- O_NDELAY | FASYNC);
- filp->f_flags |= arg & (O_APPEND | O_NONBLOCK |
- O_NDELAY | FASYNC);
+ err = setfl(filp, arg);
break;
case F_GETLK:
err = fcntl_getlk(fd, (struct flock *) arg);
@@ -186,12 +193,12 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
fasync_ok:
err = 0;
filp->f_owner = arg;
- if (S_ISSOCK (filp->f_inode->i_mode))
+ if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
err = sock_fcntl (filp, F_SETOWN, arg);
break;
default:
/* sockets need a few special fcntls. */
- if (S_ISSOCK (filp->f_inode->i_mode))
+ if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
err = sock_fcntl (filp, cmd, arg);
else
err = -EINVAL;
diff --git a/fs/fifo.c b/fs/fifo.c
index 16f4f7f61..d2eb7a80e 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -153,7 +153,6 @@ struct inode_operations fifo_inode_operations = {
void init_fifo(struct inode * inode)
{
inode->i_op = &fifo_inode_operations;
- inode->i_pipe = 1;
PIPE_LOCK(*inode) = 0;
PIPE_BASE(*inode) = NULL;
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
diff --git a/fs/file_table.c b/fs/file_table.c
index b8c8d4155..6413218ff 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -102,6 +102,24 @@ again:
return f;
}
+/*
+ * Clear and initialize a (private) struct file for the given dentry,
+ * and call the open function (if any). The caller must verify that
+ * inode->i_op and inode->i_op->default_file_ops are not NULL.
+ */
+int init_private_file(struct file *filp, struct dentry *dentry, int mode)
+{
+ memset(filp, 0, sizeof(*filp));
+ filp->f_mode = mode;
+ filp->f_count = 1;
+ filp->f_dentry = dentry;
+ 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);
+ else
+ return 0;
+}
+
#ifdef CONFIG_QUOTA
void add_dquot_ref(kdev_t dev, short type)
@@ -109,11 +127,15 @@ void add_dquot_ref(kdev_t dev, short type)
struct file *filp;
for (filp = inuse_filps; filp; filp = filp->f_next) {
- if (!filp->f_inode || filp->f_inode->i_dev != dev)
+ struct inode * inode;
+ if (!filp->f_dentry)
+ continue;
+ inode = filp->f_dentry->d_inode;
+ if (!inode || inode->i_dev != dev)
continue;
- if (filp->f_mode & FMODE_WRITE && filp->f_inode->i_sb->dq_op) {
- filp->f_inode->i_sb->dq_op->initialize(filp->f_inode, type);
- filp->f_inode->i_flags |= S_WRITE;
+ if (filp->f_mode & FMODE_WRITE && inode->i_sb->dq_op) {
+ inode->i_sb->dq_op->initialize(inode, type);
+ inode->i_flags |= S_WRITE;
}
}
}
@@ -123,11 +145,15 @@ void reset_dquot_ptrs(kdev_t dev, short type)
struct file *filp;
for (filp = inuse_filps; filp; filp = filp->f_next) {
- if (!filp->f_inode || filp->f_inode->i_dev != dev)
+ struct inode * inode;
+ if (!filp->f_dentry)
+ continue;
+ inode = filp->f_dentry->d_inode;
+ if (!inode || inode->i_dev != dev)
continue;
- if (IS_WRITABLE(filp->f_inode)) {
- filp->f_inode->i_dquot[type] = NODQUOT;
- filp->f_inode->i_flags &= ~S_WRITE;
+ if (IS_WRITABLE(inode)) {
+ inode->i_dquot[type] = NODQUOT;
+ inode->i_flags &= ~S_WRITE;
}
}
}
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 004ee0aff..74016aa67 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -8,7 +8,6 @@
#include <linux/config.h>
#include <linux/fs.h>
-#include <linux/nametrans.h>
#include <linux/minix_fs.h>
#include <linux/ext2_fs.h>
@@ -45,10 +44,6 @@ __initfunc(static void do_sys_setup(void))
binfmt_setup();
-#ifdef CONFIG_TRANS_NAMES
- init_nametrans();
-#endif
-
#ifdef CONFIG_EXT2_FS
init_ext2_fs();
#endif
diff --git a/fs/inode.c b/fs/inode.c
index 7215e1204..8813bbd45 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1,708 +1,500 @@
/*
- * fs/inode.c
+ * linux/fs/inode.c
*
- * Complete reimplementation
- * (C) 1997 Thomas Schoebel-Theuer
+ * (C) 1997 Linus Torvalds
*/
-/* Everything here is intended to be MP-safe. However, other parts
- * of the kernel are not yet MP-safe, in particular the inode->i_count++
- * that are spread over everywhere. These should be replaced by
- * iinc() as soon as possible. Since I have no MP machine, I could
- * not test it.
- */
-#include <linux/config.h>
-#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/dlists.h>
-#include <linux/dalloc.h>
-#include <linux/omirr.h>
-
-/* #define DEBUG */
-
-#define HASH_SIZE 1024 /* must be a power of 2 */
-#define NR_LEVELS 4
-
-#define ST_AGED 1
-#define ST_HASHED 2
-#define ST_EMPTY 4
-#define ST_TO_READ 8
-#define ST_TO_WRITE 16
-#define ST_TO_PUT 32
-#define ST_TO_DROP 64
-#define ST_IO (ST_TO_READ|ST_TO_WRITE|ST_TO_PUT|ST_TO_DROP)
-#define ST_WAITING 128
-#define ST_FREEING 256
-#define ST_IBASKET 512
-
-/* The idea is to keep empty inodes in a separate list, so no search
- * is required as long as empty inodes exit.
- * All reusable inodes occurring in the hash table with i_count==0
- * are also registered in the ringlist aged_i[level], but in LRU order.
- * Used inodes with i_count>0 are kept solely in the hashtable and in
- * all_i, but in no other list.
- * The level is used for multilevel aging to avoid thrashing; each
- * time i_count decreases to 0, the inode is inserted into the next level
- * ringlist. Cache reusage is simply by taking the _last_ element from the
- * lowest-level ringlist that contains inodes.
- * In contrast to the old code, there isn't any O(n) search overhead now
- * in iget/iput (if you make HASH_SIZE large enough).
+
+/*
+ * New inode.c implementation.
+ *
+ * This implementation has the basic premise of trying
+ * to be extremely low-overhead and SMP-safe, yet be
+ * simple enough to be "obviously correct".
+ *
+ * Famous last words.
+ */
+
+/*
+ * Inode lookup is no longer as critical as it used to be:
+ * most of the lookups are going to be through the dcache.
+ */
+#define HASH_BITS 8
+#define HASH_SIZE (1UL << HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+
+/*
+ * Each inode can be on two separate lists. One is
+ * the hash list of the inode, used for lookups. The
+ * other linked list is the "type" list:
+ * "in_use" - valid inode, hashed
+ * "dirty" - valid inode, hashed, dirty.
+ * "unused" - ready to be re-used. Not hashed.
+ *
+ * The two first versions also have a dirty list, allowing
+ * for low-overhead inode sync() operations.
+ */
+
+static LIST_HEAD(inode_in_use);
+static LIST_HEAD(inode_dirty);
+static LIST_HEAD(inode_unused);
+static struct list_head inode_hashtable[HASH_SIZE];
+
+/*
+ * A simple spinlock to protect the list manipulations
+ */
+spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Statistics gathering.. Not actually done yet.
*/
-static struct inode * hashtable[HASH_SIZE];/* linked with i_hash_{next,prev} */
-static struct inode * all_i = NULL; /* linked with i_{next,prev} */
-static struct inode * empty_i = NULL; /* linked with i_{next,prev} */
-static struct inode * aged_i[NR_LEVELS+1]; /* linked with i_lru_{next,prev} */
-static int aged_reused[NR_LEVELS+1]; /* # removals from aged_i[level] */
-static int age_table[NR_LEVELS+1] = { /* You may tune this. */
- 1, 4, 10, 100, 1000
-}; /* after which # of uses to increase to the next level */
-
-/* This is for kernel/sysctl.c */
-
-/* Just aligning plain ints and arrays thereof doesn't work reliably.. */
struct {
int nr_inodes;
int nr_free_inodes;
- int aged_count[NR_LEVELS+1]; /* # in each level */
+ int dummy[10];
} inodes_stat;
int max_inodes = NR_INODE;
-unsigned long last_inode = 0;
-void inode_init(void)
+void __mark_inode_dirty(struct inode *inode)
{
- memset(hashtable, 0, sizeof(hashtable));
- memset(aged_i, 0, sizeof(aged_i));
- memset(aged_reused, 0, sizeof(aged_reused));
- memset(&inodes_stat, 0, sizeof(inodes_stat));
+ spin_lock(&inode_lock);
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, &inode_dirty);
+ spin_unlock(&inode_lock);
}
-/* Intended for short locks of the above global data structures.
- * Could be replaced with spinlocks completely, since there is
- * no blocking during manipulation of the static data; however the
- * lock in invalidate_inodes() may last relatively long.
- */
-#ifdef __SMP__
-struct semaphore vfs_sem = MUTEX;
-#endif
-
-DEF_INSERT(all,struct inode,i_next,i_prev)
-DEF_REMOVE(all,struct inode,i_next,i_prev)
-
-DEF_INSERT(lru,struct inode,i_lru_next,i_lru_prev)
-DEF_REMOVE(lru,struct inode,i_lru_next,i_lru_prev)
-
-DEF_INSERT(hash,struct inode,i_hash_next,i_hash_prev)
-DEF_REMOVE(hash,struct inode,i_hash_next,i_hash_prev)
-
-DEF_INSERT(ibasket,struct inode,i_basket_next,i_basket_prev)
-DEF_REMOVE(ibasket,struct inode,i_basket_next,i_basket_prev)
-
-#ifdef DEBUG
-extern void printpath(struct dentry * entry);
-struct inode * xtst[15000];
-int xcnt = 0;
-
-void xcheck(char * txt, struct inode * p)
+static inline void unlock_inode(struct inode *inode)
{
- int i;
- for(i=xcnt-1; i>=0; i--)
- if(xtst[i] == p)
- return;
- printk("Bogus inode %p in %s\n", p, txt);
+ clear_bit(I_LOCK, &inode->i_state);
+ wake_up(&inode->i_wait);
}
-#else
-#define xcheck(t,p) /*nothing*/
-#endif
-static inline struct inode * grow_inodes(void)
+static void __wait_on_inode(struct inode * inode)
{
- struct inode * res;
- struct inode * inode = res = (struct inode*)__get_free_page(GFP_KERNEL);
- int size = PAGE_SIZE;
- if(!inode)
- return NULL;
-
- size -= sizeof(struct inode);
- inode++;
- inodes_stat.nr_inodes++;
-#ifdef DEBUG
-xtst[xcnt++]=res;
-#endif
- while(size >= sizeof(struct inode)) {
-#ifdef DEBUG
-xtst[xcnt++]=inode;
-#endif
- inodes_stat.nr_inodes++;
- inodes_stat.nr_free_inodes++;
- insert_all(&empty_i, inode);
- inode->i_status = ST_EMPTY;
- inode++;
- size -= sizeof(struct inode);
+ struct wait_queue wait = { current, NULL };
+
+ add_wait_queue(&inode->i_wait, &wait);
+repeat:
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (test_bit(I_LOCK, &inode->i_state)) {
+ schedule();
+ goto repeat;
}
- return res;
+ remove_wait_queue(&inode->i_wait, &wait);
+ current->state = TASK_RUNNING;
}
-static inline int hash(dev_t i_dev, unsigned long i_ino)
+static inline void wait_on_inode(struct inode *inode)
{
- return ((int)i_ino ^ ((int)i_dev << 6)) & (HASH_SIZE-1);
+ if (test_bit(I_LOCK, &inode->i_state))
+ __wait_on_inode(inode);
}
-static inline blocking void wait_io(struct inode * inode, unsigned short flags)
+/*
+ * These are initializations that only need to be done
+ * once, because the fields are idempotent across use
+ * of the inode..
+ */
+static inline void init_once(struct inode * inode)
{
- while(inode->i_status & flags) {
- struct wait_queue wait = {current, NULL};
- inode->i_status |= ST_WAITING;
- vfs_unlock();
- add_wait_queue(&inode->i_wait, &wait);
- sleep_on(&inode->i_wait);
- remove_wait_queue(&inode->i_wait, &wait);
- vfs_lock();
- }
+ memset(inode, 0, sizeof(*inode));
+ init_waitqueue(&inode->i_wait);
+ INIT_LIST_HEAD(&inode->i_dentry);
+ INIT_LIST_HEAD(&inode->i_hash);
+ sema_init(&inode->i_sem, 1);
}
-static inline blocking void set_io(struct inode * inode,
- unsigned short waitflags,
- unsigned short setflags)
+
+/*
+ * Look out! This returns with the inode lock held if
+ * it got an inode..
+ */
+static struct inode * grow_inodes(void)
{
- wait_io(inode, waitflags);
- inode->i_status |= setflags;
- vfs_unlock();
+ struct inode * inode = (struct inode *)__get_free_page(GFP_KERNEL);
+
+ if (inode) {
+ int size;
+ struct inode * tmp;
+
+ spin_lock(&inode_lock);
+ size = PAGE_SIZE - 2*sizeof(struct inode);
+ tmp = inode;
+ do {
+ tmp++;
+ init_once(tmp);
+ list_add(&tmp->i_list, &inode_unused);
+ size -= sizeof(struct inode);
+ } while (size >= 0);
+ init_once(inode);
+ }
+ return inode;
}
-static inline blocking int release_io(struct inode * inode, unsigned short flags)
+static inline void write_inode(struct inode *inode)
{
- int res = 0;
- vfs_lock();
- inode->i_status &= ~flags;
- if(inode->i_status & ST_WAITING) {
- inode->i_status &= ~ST_WAITING;
- vfs_unlock();
- wake_up(&inode->i_wait);
- res = 1;
- }
- return res;
+ if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
+ inode->i_sb->s_op->write_inode(inode);
}
-static inline blocking void _io(void (*op)(struct inode*), struct inode * inode,
- unsigned short waitflags, unsigned short setflags)
+static inline void sync_list(struct list_head *head, struct list_head *clean)
{
- /* Do nothing if the same op is already in progress. */
- if(op && !(inode->i_status & setflags)) {
- set_io(inode, waitflags, setflags);
- op(inode);
- if(release_io(inode, setflags)) {
- /* Somebody grabbed my inode from under me. */
-#ifdef DEBUG
- printk("_io grab!\n");
-#endif
- vfs_lock();
+ struct list_head * tmp;
+
+ while ((tmp = head->prev) != head) {
+ struct inode *inode = list_entry(tmp, struct inode, i_list);
+ list_del(tmp);
+
+ /*
+ * If the inode is locked, it's already being written out.
+ * We have to wait for it, though.
+ */
+ if (test_bit(I_LOCK, &inode->i_state)) {
+ list_add(tmp, head);
+ spin_unlock(&inode_lock);
+ __wait_on_inode(inode);
+ } else {
+ list_add(tmp, clean);
+ clear_bit(I_DIRTY, &inode->i_state);
+ set_bit(I_LOCK, &inode->i_state);
+ spin_unlock(&inode_lock);
+ write_inode(inode);
+ unlock_inode(inode);
}
- }
+ spin_lock(&inode_lock);
+ }
}
-blocking int _free_ibasket(struct super_block * sb)
+/*
+ * "sync_inodes()" goes through the dirty list
+ * and writes them out and puts them back on
+ * the normal list.
+ */
+void sync_inodes(kdev_t dev)
{
- if(sb->s_ibasket) {
- struct inode * delinquish = sb->s_ibasket->i_basket_prev;
-#if 0
-printpath(delinquish->i_dentry);
-printk(" delinquish\n");
-#endif
- _clear_inode(delinquish, 0, 1);
- return 1;
- }
- return 0;
+ spin_lock(&inode_lock);
+ sync_list(&inode_dirty, &inode_in_use);
+ spin_unlock(&inode_lock);
}
-static /*inline*/ void _put_ibasket(struct inode * inode)
+/*
+ * This is called by the filesystem to tell us
+ * that the inode is no longer useful. We just
+ * terminate it with extreme predjudice.
+ */
+void clear_inode(struct inode *inode)
{
- struct super_block * sb = inode->i_sb;
- if(!(inode->i_status & ST_IBASKET)) {
- inode->i_status |= ST_IBASKET;
- insert_ibasket(&sb->s_ibasket, inode);
- sb->s_ibasket_count++;
- if(sb->s_ibasket_count > sb->s_ibasket_max)
- (void)_free_ibasket(sb);
- }
+ truncate_inode_pages(inode, 0);
+ wait_on_inode(inode);
+ if (IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op)
+ inode->i_sb->dq_op->drop(inode);
+
+ inode->i_state = 0;
}
-blocking void _clear_inode(struct inode * inode, int external, int verbose)
+#define CAN_UNUSE(inode) \
+ (((inode)->i_count == 0) && \
+ ((inode)->i_nrpages == 0) && \
+ (!(inode)->i_state))
+
+static void invalidate_list(struct list_head *head, kdev_t dev)
{
-xcheck("_clear_inode",inode);
- if(inode->i_status & ST_IBASKET) {
- struct super_block * sb = inode->i_sb;
- remove_ibasket(&sb->s_ibasket, inode);
- sb->s_ibasket_count--;
- inode->i_status &= ~ST_IBASKET;
-#if 0
-printpath(inode->i_dentry);
-printk(" put_inode\n");
-#endif
- _io(sb->s_op->put_inode, inode, ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
- if(inode->i_status & ST_EMPTY)
- return;
+ struct list_head *next;
+
+ next = head->next;
+ for (;;) {
+ struct list_head * tmp = next;
+ struct inode * inode;
+
+ next = next->next;
+ if (tmp == head)
+ break;
+ inode = list_entry(tmp, struct inode, i_list);
+ if (inode->i_dev != dev)
+ continue;
+ if (!CAN_UNUSE(inode))
+ continue;
+ list_del(&inode->i_hash);
+ INIT_LIST_HEAD(&inode->i_hash);
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, &inode_unused);
}
- if(inode->i_status & ST_HASHED)
- remove_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
- if(inode->i_status & ST_AGED) {
- /* "cannot happen" when called from an fs because at least
- * the caller must use it. Can happen when called from
- * invalidate_inodes(). */
- if(verbose)
- printk("VFS: clearing aged inode\n");
- if(atomic_read(&inode->i_count))
- printk("VFS: aged inode is in use\n");
- remove_lru(&aged_i[inode->i_level], inode);
- inodes_stat.aged_count[inode->i_level]--;
- }
- if(!external && inode->i_status & ST_IO) {
- printk("VFS: clearing inode during IO operation\n");
- }
- if(!(inode->i_status & ST_EMPTY)) {
- remove_all(&all_i, inode);
- inode->i_status = ST_EMPTY;
- while(inode->i_dentry) {
- d_del(inode->i_dentry, D_NO_CLEAR_INODE);
- }
- if(inode->i_pages) {
- vfs_unlock(); /* may block, can that be revised? */
- truncate_inode_pages(inode, 0);
- vfs_lock();
- }
- insert_all(&empty_i, inode);
- inodes_stat.nr_free_inodes++;
- } else if(external)
- printk("VFS: empty inode is unnecessarily cleared multiple "
- "times by an fs\n");
- else
- printk("VFS: clearing empty inode\n");
- inode->i_status = ST_EMPTY;
- /* The inode is not really cleared any more here, but only once
- * when taken from empty_i. This saves instructions and processor
- * cache pollution.
- */
}
-void insert_inode_hash(struct inode * inode)
+void invalidate_inodes(kdev_t dev)
{
-xcheck("insert_inode_hash",inode);
- vfs_lock();
- if(!(inode->i_status & ST_HASHED)) {
- insert_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
- inode->i_status |= ST_HASHED;
- } else
- printk("VFS: trying to hash an inode again\n");
- vfs_unlock();
+ spin_lock(&inode_lock);
+ invalidate_list(&inode_in_use, dev);
+ invalidate_list(&inode_dirty, dev);
+ spin_unlock(&inode_lock);
}
-blocking struct inode * _get_empty_inode(void)
+/*
+ * This is called with the inode lock held. It just looks at the last
+ * inode on the in-use list, and if the inode is trivially freeable
+ * we just move it to the unused list.
+ *
+ * Otherwise we just move the inode to be the first inode and expect to
+ * get back to the problem later..
+ */
+static void try_to_free_inodes(void)
{
- struct inode * inode;
- int retry = 0;
-
-retry:
- inode = empty_i;
- if(inode) {
- remove_all(&empty_i, inode);
- inodes_stat.nr_free_inodes--;
- } else if(inodes_stat.nr_inodes < max_inodes || retry > 2) {
- inode = grow_inodes();
- }
- if(!inode) {
- int level;
- int usable = 0;
- for(level = 0; level <= NR_LEVELS; level++)
- if(aged_i[level]) {
- inode = aged_i[level]->i_lru_prev;
- /* Here is the picking strategy, tune this */
- if(aged_reused[level] < (usable++ ?
- inodes_stat.aged_count[level] :
- 2))
- break;
- aged_reused[level] = 0;
- }
- if(inode) {
- if(!(inode->i_status & ST_AGED))
- printk("VFS: inode aging inconsistency\n");
- if(atomic_read(&inode->i_count) + inode->i_ddir_count)
- printk("VFS: i_count of aged inode is not zero\n");
- if(inode->i_dirt)
- printk("VFS: Hey, somebody made my aged inode dirty\n");
- _clear_inode(inode, 0, 0);
- goto retry;
+ struct list_head * tmp;
+ struct list_head *head = &inode_in_use;
+
+ tmp = head->prev;
+ if (tmp != head) {
+ struct inode * inode;
+
+ list_del(tmp);
+ inode = list_entry(tmp, struct inode, i_list);
+ if (CAN_UNUSE(inode)) {
+ list_del(&inode->i_hash);
+ INIT_LIST_HEAD(&inode->i_hash);
+ head = &inode_unused;
}
+ list_add(tmp, head);
}
- if(!inode) {
- vfs_unlock();
- schedule();
- if(retry > 10)
- panic("VFS: cannot repair inode shortage");
- if(retry > 2)
- printk("VFS: no free inodes\n");
- retry++;
- vfs_lock();
- goto retry;
- }
-xcheck("get_empty_inode",inode);
- memset(inode, 0, sizeof(struct inode));
- atomic_set(&inode->i_count, 1);
- inode->i_nlink = 1;
- sema_init(&inode->i_sem, 1);
- inode->i_ino = ++last_inode;
- inode->i_version = ++event;
- insert_all(&all_i, inode);
- return inode;
}
+
-static inline blocking struct inode * _get_empty_inode_hashed(dev_t i_dev,
- unsigned long i_ino)
+static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head)
{
- struct inode ** base = &hashtable[hash(i_dev, i_ino)];
- struct inode * inode = *base;
- if(inode) do {
- if(inode->i_ino == i_ino && inode->i_dev == i_dev) {
- atomic_inc(&inode->i_count);
- printk("VFS: inode %lx is already in use\n", i_ino);
- return inode;
- }
- inode = inode->i_hash_next;
- } while(inode != *base);
- inode = _get_empty_inode();
- inode->i_dev = i_dev;
- inode->i_ino = i_ino;
- insert_hash(base, inode);
- inode->i_status |= ST_HASHED;
+ struct list_head *tmp;
+ struct inode * inode;
+
+ tmp = head;
+ for (;;) {
+ tmp = tmp->next;
+ inode = NULL;
+ if (tmp == head)
+ break;
+ inode = list_entry(tmp, struct inode, i_hash);
+ if (inode->i_sb != sb)
+ continue;
+ if (inode->i_ino != ino)
+ continue;
+ inode->i_count++;
+ break;
+ }
return inode;
}
-blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino)
+/*
+ * This just initializes the inode fields
+ * to known values before returning the inode..
+ *
+ * i_sb, i_ino, i_count, i_state and the lists have
+ * been initialized elsewhere..
+ */
+void clean_inode(struct inode *inode)
{
- struct inode * inode;
-
- vfs_lock();
- inode = _get_empty_inode_hashed(i_dev, i_ino);
- vfs_unlock();
- return inode;
+ memset(&inode->u, 0, sizeof(inode->u));
+ inode->i_sock = 0;
+ inode->i_op = NULL;
+ inode->i_nlink = 1;
+ inode->i_writecount = 0;
+ inode->i_size = 0;
+ memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+ sema_init(&inode->i_sem, 1);
}
-void _get_inode(struct inode * inode)
+/*
+ * 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)
{
- if(inode->i_status & ST_IBASKET) {
- inode->i_status &= ~ST_IBASKET;
- remove_ibasket(&inode->i_sb->s_ibasket, inode);
- inode->i_sb->s_ibasket_count--;
- }
- if(inode->i_status & ST_AGED) {
- inode->i_status &= ~ST_AGED;
- remove_lru(&aged_i[inode->i_level], inode);
- inodes_stat.aged_count[inode->i_level]--;
- aged_reused[inode->i_level]++;
- if(S_ISDIR(inode->i_mode))
- /* make dirs less thrashable */
- inode->i_level = NR_LEVELS-1;
- else if(inode->i_nlink > 1)
- /* keep hardlinks totally separate */
- inode->i_level = NR_LEVELS;
- else if(++inode->i_reuse_count >= age_table[inode->i_level]
- && inode->i_level < NR_LEVELS-1)
- inode->i_level++;
- if(atomic_read(&inode->i_count) != 1)
- printk("VFS: inode count was not zero\n");
- } else if(inode->i_status & ST_EMPTY)
- printk("VFS: invalid reuse of empty inode\n");
+ sb->s_op->read_inode(inode);
+ unlock_inode(inode);
}
-blocking struct inode * __iget(struct super_block * sb,
- unsigned long i_ino,
- int crossmntp)
+struct inode * get_empty_inode(void)
{
- struct inode ** base;
+ static unsigned long last_ino = 0;
struct inode * inode;
- dev_t i_dev;
-
- if(!sb)
- panic("VFS: iget with sb == NULL");
- i_dev = sb->s_dev;
- if(!i_dev)
- panic("VFS: sb->s_dev is NULL\n");
- base = &hashtable[hash(i_dev, i_ino)];
- vfs_lock();
- inode = *base;
- if(inode) do {
- if(inode->i_ino == i_ino && inode->i_dev == i_dev) {
- atomic_inc(&inode->i_count);
- _get_inode(inode);
-
- /* Allow concurrent writes/puts. This is in particular
- * useful e.g. when syncing large chunks.
- * I hope the i_dirty flag is everywhere set as soon
- * as _any_ modifcation is made and _before_
- * giving up control, so no harm should occur if data
- * is modified during writes, because it will be
- * rewritten again (does a short inconsistency on the
- * disk harm?)
- */
- wait_io(inode, ST_TO_READ);
- vfs_unlock();
- goto done;
- }
- inode = inode->i_hash_next;
- } while(inode != *base);
- inode = _get_empty_inode_hashed(i_dev, i_ino);
- inode->i_sb = sb;
- inode->i_flags = sb->s_flags;
- if(sb->s_op && sb->s_op->read_inode) {
- set_io(inode, 0, ST_TO_READ); /* do not wait at all */
- sb->s_op->read_inode(inode);
- if(release_io(inode, ST_TO_READ))
- goto done;
- }
- vfs_unlock();
-done:
- while(crossmntp && inode->i_mount) {
- struct inode * tmp = inode->i_mount;
- iinc(tmp);
- iput(inode);
- inode = tmp;
+ struct list_head * tmp;
+
+ spin_lock(&inode_lock);
+ try_to_free_inodes();
+ tmp = inode_unused.next;
+ if (tmp != &inode_unused) {
+ list_del(tmp);
+ inode = list_entry(tmp, struct inode, i_list);
+add_new_inode:
+ inode->i_sb = NULL;
+ inode->i_ino = ++last_ino;
+ inode->i_count = 1;
+ list_add(&inode->i_list, &inode_in_use);
+ inode->i_state = 0;
+ spin_unlock(&inode_lock);
+ clean_inode(inode);
+ return inode;
}
-xcheck("_iget",inode);
+
+ /*
+ * Warning: if this succeeded, we will now
+ * return with the inode lock.
+ */
+ spin_unlock(&inode_lock);
+ inode = grow_inodes();
+ if (inode)
+ goto add_new_inode;
+
return inode;
}
-blocking void __iput(struct inode * inode)
+/*
+ * This is called with the inode lock held.. Be careful.
+ */
+static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head)
{
- struct super_block * sb;
-xcheck("_iput",inode);
- if(atomic_read(&inode->i_count) + inode->i_ddir_count < 0)
- printk("VFS: i_count is negative\n");
- if((atomic_read(&inode->i_count) + inode->i_ddir_count) ||
- (inode->i_status & ST_FREEING)) {
- return;
- }
- inode->i_status |= ST_FREEING;
-#ifdef CONFIG_OMIRR
- if(inode->i_status & ST_MODIFIED) {
- inode->i_status &= ~ST_MODIFIED;
- omirr_printall(inode, " W %ld ", CURRENT_TIME);
- }
-#endif
- if(inode->i_pipe) {
- free_page((unsigned long)PIPE_BASE(*inode));
- PIPE_BASE(*inode)= NULL;
- }
- if((sb = inode->i_sb)) {
- if(sb->s_type && (sb->s_type->fs_flags & FS_NO_DCACHE)) {
- while(inode->i_dentry)
- d_del(inode->i_dentry, D_NO_CLEAR_INODE);
- if(atomic_read(&inode->i_count) + inode->i_ddir_count)
- goto done;
- }
- if(sb->s_op) {
- if(inode->i_nlink <= 0 && inode->i_dent_count &&
- !(inode->i_status & (ST_EMPTY|ST_IBASKET)) &&
- (sb->s_type->fs_flags & FS_IBASKET)) {
- _put_ibasket(inode);
- goto done;
- }
- if(!inode->i_dent_count ||
- (sb->s_type->fs_flags & FS_NO_DCACHE)) {
- _io(sb->s_op->put_inode, inode,
- ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
- if(atomic_read(&inode->i_count) + inode->i_ddir_count)
- goto done;
- if(inode->i_nlink <= 0) {
- if(!(inode->i_status & ST_EMPTY)) {
- _clear_inode(inode, 0, 1);
- }
- goto done;
- }
- }
- if(inode->i_dirt) {
- inode->i_dirt = 0;
- _io(sb->s_op->write_inode, inode,
- ST_TO_PUT|ST_TO_WRITE, ST_TO_WRITE);
- if(atomic_read(&inode->i_count) + inode->i_ddir_count)
- goto done;
- }
- }
- if(IS_WRITABLE(inode) && sb->dq_op) {
- /* can operate in parallel to other ops ? */
- _io(sb->dq_op->drop, inode, 0, ST_TO_DROP);
- if(atomic_read(&inode->i_count) + inode->i_ddir_count)
- goto done;
- }
- }
- if(inode->i_mmap)
- printk("VFS: inode has mappings\n");
- if(inode->i_status & ST_AGED) {
- printk("VFS: reaging inode\n");
-#if defined(DEBUG)
-printpath(inode->i_dentry);
-printk("\n");
-#endif
- goto done;
- }
- if(!(inode->i_status & (ST_HASHED|ST_EMPTY))) {
- _clear_inode(inode, 0, 1);
- goto done;
+ struct inode * inode;
+ struct list_head * tmp = inode_unused.next;
+
+ if (tmp != &inode_unused) {
+ list_del(tmp);
+ inode = list_entry(tmp, struct inode, i_list);
+add_new_inode:
+ list_add(&inode->i_list, &inode_in_use);
+ list_add(&inode->i_hash, head);
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_ino = ino;
+ inode->i_flags = sb->s_flags;
+ inode->i_count = 1;
+ inode->i_state = 1 << I_LOCK;
+ spin_unlock(&inode_lock);
+ clean_inode(inode);
+ read_inode(inode, sb);
+ return inode;
}
- if(inode->i_status & ST_EMPTY) {
- printk("VFS: aging an empty inode\n");
- goto done;
+
+ /*
+ * Uhhuh.. We need to expand. Unlock for the allocation,
+ * but note that "grow_inodes()" will return with the
+ * lock held again if the allocation succeeded.
+ */
+ spin_unlock(&inode_lock);
+ inode = grow_inodes();
+ if (inode) {
+ /* We released the lock, so.. */
+ struct inode * old = find_inode(sb, ino, head);
+ if (!old)
+ goto add_new_inode;
+ list_add(&inode->i_list, &inode_unused);
+ spin_unlock(&inode_lock);
+ wait_on_inode(old);
+ return old;
}
- insert_lru(&aged_i[inode->i_level], inode);
- inodes_stat.aged_count[inode->i_level]++;
- inode->i_status |= ST_AGED;
-done:
- inode->i_status &= ~ST_FREEING;
+ return inode;
}
-blocking void _iput(struct inode * inode)
+static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
{
- vfs_lock();
- __iput(inode);
- vfs_unlock();
+ unsigned long tmp = i_ino | (unsigned long) sb;
+ tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
+ return tmp & HASH_MASK;
}
-blocking void sync_inodes(kdev_t dev)
+struct inode *iget(struct super_block *sb, unsigned long ino)
{
+ struct list_head * head = inode_hashtable + hash(sb,ino);
struct inode * inode;
- vfs_lock();
- inode = all_i;
- if(inode) do {
-xcheck("sync_inodes",inode);
- if(inode->i_dirt && (inode->i_dev == dev || !dev)) {
- if(inode->i_sb && inode->i_sb->s_op &&
- !(inode->i_status & ST_FREEING)) {
- inode->i_dirt = 0;
- _io(inode->i_sb->s_op->write_inode, inode,
- ST_IO, ST_TO_WRITE);
- }
- }
- inode = inode->i_next;
- } while(inode != all_i);
- vfs_unlock();
+
+ spin_lock(&inode_lock);
+ inode = find_inode(sb, ino, head);
+ if (!inode) {
+ try_to_free_inodes();
+ return get_new_inode(sb, ino, head);
+ }
+ spin_unlock(&inode_lock);
+ wait_on_inode(inode);
+ return inode;
}
-blocking int _check_inodes(kdev_t dev, int complain)
+void insert_inode_hash(struct inode *inode)
{
- struct inode * inode;
- int bad = 0;
-
- vfs_lock();
-startover:
- inode = all_i;
- if(inode) do {
- struct inode * next;
-xcheck("_check_inodes",inode);
- next = inode->i_next;
- if(inode->i_dev == dev) {
- if(inode->i_dirt || atomic_read(&inode->i_count)) {
- bad++;
- } else {
- _clear_inode(inode, 0, 0);
-
- /* _clear_inode() may recursively clear other
- * inodes, probably also the next one.
- */
- if(next->i_status & ST_EMPTY)
- goto startover;
- }
- }
- inode = next;
- } while(inode != all_i);
- vfs_unlock();
- if(complain && bad)
- printk("VFS: %d inode(s) busy on removed device `%s'\n",
- bad, kdevname(dev));
- return (bad == 0);
+ struct list_head *head = inode_hashtable + hash(inode->i_sb, inode->i_ino);
+ list_add(&inode->i_hash, head);
}
-/*inline*/ void invalidate_inodes(kdev_t dev)
+void iput(struct inode *inode)
{
- /* Requires two passes, because of the new dcache holding
- * directories with i_count > 1.
- */
- (void)_check_inodes(dev, 0);
- (void)_check_inodes(dev, 1);
+ if (inode) {
+ struct super_operations *op = NULL;
+
+ if (inode->i_sb && inode->i_sb->s_op)
+ op = inode->i_sb->s_op;
+ if (op && op->put_inode)
+ op->put_inode(inode);
+
+ spin_lock(&inode_lock);
+ if (!--inode->i_count) {
+ if (!inode->i_nlink) {
+ list_del(&inode->i_hash);
+ INIT_LIST_HEAD(&inode->i_hash);
+ list_del(&inode->i_list);
+ INIT_LIST_HEAD(&inode->i_list);
+ if (op && op->delete_inode) {
+ void (*delete)(struct inode *) = op->delete_inode;
+ spin_unlock(&inode_lock);
+ delete(inode);
+ spin_lock(&inode_lock);
+ }
+ }
+ if (list_empty(&inode->i_hash)) {
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, &inode_unused);
+ }
+ }
+ spin_unlock(&inode_lock);
+ }
}
-/*inline*/ int fs_may_mount(kdev_t dev)
+int bmap(struct inode * inode, int block)
{
- return _check_inodes(dev, 0);
+ if (inode->i_op && inode->i_op->bmap)
+ return inode->i_op->bmap(inode, block);
+ return 0;
}
-int fs_may_remount_ro(kdev_t dev)
+/*
+ * Initialize the hash tables
+ */
+void inode_init(void)
{
- (void)dev;
- return 1; /* not checked any more */
+ int i;
+ struct list_head *head = inode_hashtable;
+
+ i = HASH_SIZE;
+ do {
+ INIT_LIST_HEAD(head);
+ head++;
+ i--;
+ } while (i);
}
-int fs_may_umount(kdev_t dev, struct inode * mount_root)
+/*
+ * FIXME! These need to go through the in-use inodes to
+ * check whether we can mount/umount/remount.
+ */
+int fs_may_mount(kdev_t dev)
{
- struct inode * inode;
- vfs_lock();
- inode = all_i;
- if(inode) do {
-xcheck("fs_may_umount",inode);
- if(inode->i_dev == dev && atomic_read(&inode->i_count))
- if(inode != mount_root || atomic_read(&inode->i_count) >
- (inode->i_mount == inode ? 2 : 1)) {
- vfs_unlock();
- return 0;
- }
- inode = inode->i_next;
- } while(inode != all_i);
- vfs_unlock();
return 1;
}
-extern struct inode_operations pipe_inode_operations;
-
-blocking struct inode * get_pipe_inode(void)
+int fs_may_umount(struct super_block *sb, struct dentry * root)
{
- struct inode * inode = get_empty_inode();
-
- PIPE_BASE(*inode) = (char*)__get_free_page(GFP_USER);
- if(!(PIPE_BASE(*inode))) {
- iput(inode);
- return NULL;
- }
- inode->i_blksize = PAGE_SIZE;
- inode->i_pipe = 1;
- inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
- atomic_inc(&inode->i_count);
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_op = &pipe_inode_operations;
- PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
-
- /* I hope this does not introduce security problems.
- * Please check and give me response.
- */
- {
- char dummyname[32];
- struct qstr dummy = { dummyname, 0 };
- struct dentry * new;
- sprintf(dummyname, ".anonymous-pipe-%06lud", inode->i_ino);
- dummy.len = strlen(dummyname);
- vfs_lock();
- new = d_alloc(the_root, dummy.len, 0);
- if(new)
- d_add(new, inode, &dummy, D_BASKET);
- vfs_unlock();
- }
- return inode;
+ shrink_dcache();
+ return root->d_count == 1;
}
-int bmap(struct inode * inode, int block)
+int fs_may_remount_ro(struct super_block *sb)
{
- if (inode->i_op && inode->i_op->bmap)
- return inode->i_op->bmap(inode, block);
- return 0;
+ return 1;
}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 6766506a8..11798a238 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -20,28 +20,27 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
int error;
int block;
+ struct inode * inode = filp->f_dentry->d_inode;
switch (cmd) {
case FIBMAP:
- if (filp->f_inode->i_op == NULL)
+ if (inode->i_op == NULL)
return -EBADF;
- if (filp->f_inode->i_op->bmap == NULL)
+ if (inode->i_op->bmap == NULL)
return -EINVAL;
if ((error = get_user(block, (int *) arg)) != 0)
return error;
- block = filp->f_inode->i_op->bmap(filp->f_inode,block);
+ block = inode->i_op->bmap(inode,block);
return put_user(block, (int *) arg);
case FIGETBSZ:
- if (filp->f_inode->i_sb == NULL)
+ if (inode->i_sb == NULL)
return -EBADF;
- return put_user(filp->f_inode->i_sb->s_blocksize,
- (int *) arg);
+ return put_user(inode->i_sb->s_blocksize, (int *) arg);
case FIONREAD:
- return put_user(filp->f_inode->i_size - filp->f_pos,
- (int *) arg);
+ return put_user(inode->i_size - filp->f_pos, (int *) arg);
}
if (filp->f_op && filp->f_op->ioctl)
- return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
+ return filp->f_op->ioctl(inode, filp, cmd, arg);
return -ENOTTY;
}
@@ -91,10 +90,10 @@ asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
break;
default:
- if (filp->f_inode && S_ISREG(filp->f_inode->i_mode))
+ if (filp->f_dentry && filp->f_dentry->d_inode && S_ISREG(filp->f_dentry->d_inode->i_mode))
error = file_ioctl(filp, cmd, arg);
else if (filp->f_op && filp->f_op->ioctl)
- error = filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
+ error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
else
error = -ENOTTY;
}
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index e22c3ca3b..48321d356 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -54,6 +54,7 @@ struct inode_operations isofs_dir_inode_operations =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
isofs_bmap, /* bmap */
@@ -61,20 +62,6 @@ struct inode_operations isofs_dir_inode_operations =
NULL /* permission */
};
-static int parent_inode_number(struct inode * inode, struct iso_directory_record * de)
-{
- int inode_number = inode->i_ino;
-
- if ((inode->i_sb->u.isofs_sb.s_firstdatazone) != inode->i_ino)
- inode_number = inode->u.isofs_i.i_backlink;
-
- if (inode_number != -1)
- return inode_number;
-
- /* This should never happen, but who knows. Try to be forgiving */
- return isofs_lookup_grandparent(inode, find_rock_ridge_relocation(de, inode));
-}
-
static int isofs_name_translate(char * old, int len, char * new)
{
int i, c;
@@ -196,9 +183,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
/* Handle the case of the '..' directory */
if (de->name_len[0] == 1 && de->name[0] == 1) {
- inode_number = parent_inode_number(inode, de);
- if (inode_number == -1)
- break;
+ inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
break;
filp->f_pos += de_len;
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index 2742283f7..d14a558a0 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -47,6 +47,7 @@ struct inode_operations isofs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
isofs_bmap, /* bmap */
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index d081a4cdd..436c22140 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -54,9 +54,10 @@ void isofs_put_super(struct super_block *sb)
static struct super_operations isofs_sops = {
isofs_read_inode,
- NULL, /* notify_change */
NULL, /* write_inode */
NULL, /* put_inode */
+ NULL, /* delete_inode */
+ NULL, /* notify_change */
isofs_put_super,
NULL, /* write_super */
isofs_statfs,
@@ -481,12 +482,12 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->u.isofs_sb.s_mode = opt.mode & 0777;
s->s_blocksize = opt.blocksize;
s->s_blocksize_bits = blocksize_bits;
- s->s_mounted = iget(s, (isonum_733(rootp->extent) +
+ s->s_root = d_alloc_root(iget(s, (isonum_733(rootp->extent) +
isonum_711(rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size);
+ << s -> u.isofs_sb.s_log_zone_size), NULL);
unlock_super(s);
- if (!(s->s_mounted)) {
+ if (!(s->s_root)) {
s->s_dev = 0;
printk("get root inode failed\n");
MOD_DEC_USE_COUNT;
@@ -504,7 +505,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
return NULL;
}
-void isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
+int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
@@ -517,7 +518,7 @@ void isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
tmp.f_files = sb->u.isofs_sb.s_ninodes;
tmp.f_ffree = 0;
tmp.f_namelen = NAME_MAX;
- copy_to_user(buf, &tmp, bufsiz);
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
int isofs_bmap(struct inode * inode,int block)
@@ -663,7 +664,6 @@ void isofs_read_inode(struct inode * inode)
isonum_711 (raw_inode->ext_attr_length))
<< inode -> i_sb -> u.isofs_sb.s_log_zone_size;
- inode->u.isofs_i.i_backlink = 0xffffffff; /* Will be used for previous directory */
switch (inode->i_sb->u.isofs_sb.s_conversion){
case 'a':
inode->u.isofs_i.i_file_format = ISOFS_FILE_UNKNOWN; /* File type */
@@ -735,7 +735,6 @@ void isofs_read_inode(struct inode * inode)
/* With a data error we return this information */
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
inode->u.isofs_i.i_first_extent = 0;
- inode->u.isofs_i.i_backlink = 0xffffffff;
inode->i_size = 0;
inode->i_nlink = 1;
inode->i_uid = inode->i_gid = 0;
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 155f4ae43..1c0be7fde 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -59,14 +59,13 @@ static int isofs_match(int len,const char * name, const char * compare, int dlen
* entry - you'll have to do that yourself if you want to.
*/
static struct buffer_head * isofs_find_entry(struct inode * dir,
- const char * name, int namelen, unsigned long * ino, unsigned long * ino_back)
+ const char * name, int namelen, unsigned long * ino)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
unsigned int block, i, f_pos, offset, inode_number;
struct buffer_head * bh;
unsigned int old_offset;
- unsigned int backlink;
int dlen, rrflag, match;
char * dpnt;
struct iso_directory_record * de;
@@ -86,7 +85,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
while (f_pos < dir->i_size) {
de = (struct iso_directory_record *) (bh->b_data + offset);
- backlink = dir->i_ino;
inode_number = (block << bufbits) + (offset & (bufsize - 1));
/* If byte is zero, this is the end of file, or time to move to
@@ -120,28 +118,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
return 0;
}
- /* Handle the '.' case */
-
- if (de->name[0]==0 && de->name_len[0]==1) {
- inode_number = dir->i_ino;
- backlink = 0;
- }
-
- /* Handle the '..' case */
-
- if (de->name[0]==1 && de->name_len[0]==1) {
-#if 0
- printk("Doing .. (%d %d)",
- dir->i_sb->s_firstdatazone,
- dir->i_ino);
-#endif
- if((dir->i_sb->u.isofs_sb.s_firstdatazone) != dir->i_ino)
- inode_number = dir->u.isofs_i.i_backlink;
- else
- inode_number = dir->i_ino;
- backlink = 0;
- }
-
dlen = de->name_len[0];
dpnt = de->name;
/* Now convert the filename in the buffer to lower case */
@@ -183,16 +159,8 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
inode_number =
isofs_lookup_grandparent(dir,
find_rock_ridge_relocation(de,dir));
- if(inode_number == -1){
- /* Should never happen */
- printk("Backlink not properly set %x %lx.\n",
- isonum_733(de->extent),
- dir->i_ino);
- goto out;
- }
}
*ino = inode_number;
- *ino_back = backlink;
return bh;
}
}
@@ -201,62 +169,48 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
return NULL;
}
-int isofs_lookup(struct inode * dir,const char * name, int len,
- struct inode ** result)
+int isofs_lookup(struct inode * dir, struct dentry * dentry)
{
- unsigned long ino, ino_back;
+ unsigned long ino;
struct buffer_head * bh;
char *lcname;
+ struct inode *inode;
#ifdef DEBUG
- printk("lookup: %x %d\n",dir->i_ino, len);
+ printk("lookup: %x %d\n",dir->i_ino, dentry->d_name.len);
#endif
- *result = NULL;
if (!dir)
return -ENOENT;
- if (!S_ISDIR(dir->i_mode)) {
- iput(dir);
+ if (!S_ISDIR(dir->i_mode))
return -ENOENT;
- }
/* If mounted with check=relaxed (and most likely norock),
* then first convert this name to lower case.
*/
if (dir->i_sb->u.isofs_sb.s_name_check == 'r' &&
- (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
+ (lcname = kmalloc(dentry->d_name.len, GFP_KERNEL)) != NULL) {
int i;
char c;
- for (i=0; i<len; i++) {
- c = name[i];
+ for (i=0; i<dentry->d_name.len; i++) {
+ c = dentry->d_name.name[i];
if (c >= 'A' && c <= 'Z') c |= 0x20;
lcname[i] = c;
}
- bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
+ bh = isofs_find_entry(dir, lcname, dentry->d_name.len, &ino);
kfree(lcname);
} else
- bh = isofs_find_entry(dir,name,len, &ino, &ino_back);
+ bh = isofs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &ino);
- if (!bh) {
- iput(dir);
- return -ENOENT;
- }
- brelse(bh);
+ inode = NULL;
+ if (bh) {
+ brelse(bh);
- if (!(*result = iget(dir->i_sb,ino))) {
- iput(dir);
- return -EACCES;
+ inode = iget(dir->i_sb,ino);
+ if (!inode)
+ return -EACCES;
}
-
- /* We need this backlink for the ".." entry unless the name that we
- * are looking up traversed a mount point (in which case the inode
- * may not even be on an iso9660 filesystem, and writing to
- * u.isofs_i would only cause memory corruption).
- */
- if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb)
- (*result)->u.isofs_i.i_backlink = ino_back;
-
- iput(dir);
+ d_add(dentry, inode);
return 0;
}
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 8c41d2f39..98814d220 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -172,7 +172,7 @@ reclaimer(void *ptr)
/* First, reclaim all locks that have been granted previously. */
do {
for (fl = file_lock_table; fl; fl = fl->fl_next) {
- inode = fl->fl_file->f_inode;
+ inode = fl->fl_file->f_dentry->d_inode;
if (inode->i_sb->s_magic == NFS_SUPER_MAGIC
&& nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr)
&& fl->fl_u.nfs_fl.state != host->h_state
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 1506a2ba6..d219de5ea 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -42,7 +42,7 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
memset(argp, 0, sizeof(*argp));
argp->cookie = nlm_cookie++;
argp->state = nsm_local_state;
- lock->fh = *NFS_FH(fl->fl_file->f_inode);
+ lock->fh = *NFS_FH(fl->fl_file->f_dentry->d_inode);
lock->caller = system_utsname.nodename;
lock->oh.data = req->a_owner;
lock->oh.len = sprintf(req->a_owner, "%d@%s",
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index b4d74f745..69a9eeb21 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -274,8 +274,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
int error;
dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %ld-%ld, bl=%d)\n",
- file->f_file.f_inode->i_dev,
- file->f_file.f_inode->i_ino,
+ file->f_file.f_dentry->d_inode->i_dev,
+ file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_type, lock->fl.fl_pid,
lock->fl.fl_start,
lock->fl.fl_end,
@@ -344,8 +344,8 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
struct file_lock *fl;
dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %ld-%ld)\n",
- file->f_file.f_inode->i_dev,
- file->f_file.f_inode->i_ino,
+ file->f_file.f_dentry->d_inode->i_dev,
+ file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_type,
lock->fl.fl_start,
lock->fl.fl_end);
@@ -375,8 +375,8 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
int error;
dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %ld-%ld)\n",
- file->f_file.f_inode->i_dev,
- file->f_file.f_inode->i_ino,
+ file->f_file.f_dentry->d_inode->i_dev,
+ file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_pid,
lock->fl.fl_start,
lock->fl.fl_end);
@@ -403,8 +403,8 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
struct nlm_block *block;
dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %ld-%ld)\n",
- file->f_file.f_inode->i_dev,
- file->f_file.f_inode->i_ino,
+ file->f_file.f_dentry->d_inode->i_dev,
+ file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_pid,
lock->fl.fl_start,
lock->fl.fl_end);
diff --git a/fs/locks.c b/fs/locks.c
index 8ca8aa183..909c2eacb 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -297,25 +297,34 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
{
struct flock flock;
struct file *filp;
+ struct dentry *dentry;
+ struct inode *inode;
struct file_lock *fl,file_lock;
int error;
if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
- return (-EBADF);
+ return -EBADF;
if (copy_from_user(&flock, l, sizeof(flock)))
- return (-EFAULT);
+ return -EFAULT;
if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
- return (-EINVAL);
+ return -EINVAL;
- if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock))
- return (-EINVAL);
+ dentry = filp->f_dentry;
+ if (!dentry)
+ return -EINVAL;
+
+ inode = dentry->d_inode;
+ if (!inode)
+ return -EINVAL;
+
+ if (!posix_make_lock(filp, &file_lock, &flock))
+ return -EINVAL;
if (filp->f_op->lock) {
- error = filp->f_op->lock(filp->f_inode, filp,
- F_GETLK, &file_lock);
+ error = filp->f_op->lock(inode, filp, F_GETLK, &file_lock);
if (error < 0)
- return (error);
+ return error;
fl = &file_lock;
} else {
fl = posix_test_lock(filp, &file_lock);
@@ -344,6 +353,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
struct file *filp;
struct file_lock file_lock;
struct flock flock;
+ struct dentry * dentry;
struct inode *inode;
int error;
@@ -351,10 +361,13 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
*/
if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
- return (-EBADF);
-
- if (!(inode = filp->f_inode))
- return (-EINVAL);
+ return -EBADF;
+
+ if (!(dentry = filp->f_dentry))
+ return -EINVAL;
+
+ if (!(inode = dentry->d_inode))
+ return -EINVAL;
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
@@ -407,7 +420,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
}
if (filp->f_op->lock != NULL) {
- error = filp->f_op->lock(filp->f_inode, filp, cmd, &file_lock);
+ error = filp->f_op->lock(inode, filp, cmd, &file_lock);
if (error < 0)
return (error);
}
@@ -421,12 +434,14 @@ void locks_remove_locks(struct task_struct *task, struct file *filp)
{
struct file_lock file_lock, *fl;
struct file_lock **before;
+ struct inode * inode;
/* For POSIX locks we free all locks on this file for the given task.
* For FLOCK we only free locks on this *open* file if it is the last
* close on that file.
*/
- before = &filp->f_inode->i_flock;
+ inode = filp->f_dentry->d_inode;
+ before = &inode->i_flock;
while ((fl = *before) != NULL) {
if (((fl->fl_flags & FL_POSIX) && (fl->fl_owner == task)) ||
@@ -436,10 +451,9 @@ void locks_remove_locks(struct task_struct *task, struct file *filp)
locks_delete_lock(before, 0);
if (filp->f_op->lock) {
file_lock.fl_type = F_UNLCK;
- filp->f_op->lock(filp->f_inode, filp,
- F_SETLK, &file_lock);
+ filp->f_op->lock(inode, filp, F_SETLK, &file_lock);
/* List may have changed: */
- before = &filp->f_inode->i_flock;
+ before = &inode->i_flock;
}
} else {
before = &fl->fl_next;
@@ -454,7 +468,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
{
struct file_lock *cfl;
- for (cfl = filp->f_inode->i_flock; cfl; cfl = cfl->fl_next) {
+ for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
if (!(cfl->fl_flags & FL_POSIX))
continue;
if (posix_locks_conflict(cfl, fl))
@@ -585,7 +599,7 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
start = filp->f_pos;
break;
case 2: /*SEEK_END*/
- start = filp->f_inode->i_size;
+ start = filp->f_dentry->d_inode->i_size;
break;
default:
return (0);
@@ -612,7 +626,7 @@ static int flock_make_lock(struct file *filp, struct file_lock *fl,
{
memset(fl, 0, sizeof(*fl));
- if (!filp->f_inode) /* just in case */
+ if (!filp->f_dentry) /* just in case */
return (0);
switch (cmd & ~LOCK_NB) {
@@ -750,9 +764,10 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
struct file_lock *fl;
struct file_lock *new_fl;
struct file_lock **before;
+ struct inode * inode = filp->f_dentry->d_inode;
int change = 0;
- before = &filp->f_inode->i_flock;
+ before = &inode->i_flock;
while (((fl = *before) != NULL) && (fl->fl_flags & FL_FLOCK)) {
if (caller->fl_file == fl->fl_file) {
if (caller->fl_type == fl->fl_type)
@@ -772,7 +787,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
if ((new_fl = locks_alloc_lock(caller)) == NULL)
return (-ENOLCK);
repeat:
- for (fl = filp->f_inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK);
+ for (fl = inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK);
fl = fl->fl_next) {
if (!flock_locks_conflict(new_fl, fl))
continue;
@@ -801,7 +816,7 @@ repeat:
}
goto repeat;
}
- locks_insert_lock(&filp->f_inode->i_flock, new_fl);
+ locks_insert_lock(&inode->i_flock, new_fl);
return (0);
}
@@ -825,11 +840,12 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
struct file_lock *left = NULL;
struct file_lock *right = NULL;
struct file_lock **before;
+ struct inode * inode = filp->f_dentry->d_inode;
int added = 0;
if (caller->fl_type != F_UNLCK) {
repeat:
- for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
+ for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
if (!posix_locks_conflict(caller, fl))
@@ -852,7 +868,7 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
/* Find the first old lock with the same owner as the new lock.
*/
- before = &filp->f_inode->i_flock;
+ before = &inode->i_flock;
/* First skip locks owned by other processes.
*/
@@ -1054,7 +1070,7 @@ static char *lock_get_status(struct file_lock *fl, int id, char *pfx)
char *p = temp;
struct inode *inode;
- inode = fl->fl_file->f_inode;
+ inode = fl->fl_file->f_dentry->d_inode;
p += sprintf(p, "%d:%s ", id, pfx);
if (fl->fl_flags & FL_POSIX) {
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 81ac9b047..f47f779d5 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -191,8 +191,8 @@ void minix_free_inode(struct inode * inode)
printk("free_inode: inode has no device\n");
return;
}
- if (atomic_read(&inode->i_count) != 1) {
- printk("free_inode: inode has count=%d\n",atomic_read(&inode->i_count));
+ if (inode->i_count != 1) {
+ printk("free_inode: inode has count=%d\n",inode->i_count);
return;
}
if (inode->i_nlink) {
@@ -251,12 +251,12 @@ struct inode * minix_new_inode(const struct inode * dir)
iput(inode);
return NULL;
}
- atomic_set(&inode->i_count, 1);
+ inode->i_count = 1;
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
inode->i_ino = j;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = NULL;
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 439005f4e..ec5113c4a 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -50,6 +50,7 @@ struct inode_operations minix_dir_inode_operations = {
minix_mknod, /* mknod */
minix_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 86cbca2b2..7ca7cb075 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -58,6 +58,7 @@ struct inode_operations minix_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
minix_bmap, /* bmap */
@@ -120,6 +121,6 @@ static long minix_file_write(struct inode * inode, struct file * filp,
inode->i_size = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return written;
}
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index cbd735ef1..898f56f19 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -24,10 +24,8 @@
#include <asm/uaccess.h>
#include <asm/bitops.h>
-void minix_put_inode(struct inode *inode)
+static void minix_delete_inode(struct inode *inode)
{
- if (inode->i_nlink)
- return;
inode->i_size = 0;
minix_truncate(inode);
minix_free_inode(inode);
@@ -77,9 +75,10 @@ void minix_put_super(struct super_block *sb)
static struct super_operations minix_sops = {
minix_read_inode,
- NULL,
minix_write_inode,
- minix_put_inode,
+ NULL, /* put_inode */
+ minix_delete_inode,
+ NULL, /* notify_change */
minix_put_super,
minix_write_super,
minix_statfs,
@@ -125,15 +124,13 @@ int minix_remount (struct super_block * sb, int * flags, char * data)
* it really _is_ a minix filesystem, and to check the size
* of the directory entry.
*/
-static const char * minix_checkroot(struct super_block *s)
+static const char * minix_checkroot(struct super_block *s, struct inode *dir)
{
- struct inode * dir;
struct buffer_head *bh;
struct minix_dir_entry *de;
const char * errmsg;
int dirsize;
- dir = s->s_mounted;
if (!S_ISDIR(dir->i_mode))
return "root directory is not a directory";
@@ -172,7 +169,8 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
int i, block;
kdev_t dev = s->s_dev;
const char * errmsg;
-
+ struct inode *root_inode;
+
if (32 != sizeof (struct minix_inode))
panic("bad V1 i-node size");
if (64 != sizeof(struct minix2_inode))
@@ -272,8 +270,9 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
/* set up enough so that it can read an inode */
s->s_dev = dev;
s->s_op = &minix_sops;
- s->s_mounted = iget(s,MINIX_ROOT_INO);
- if (!s->s_mounted) {
+ root_inode = iget(s,MINIX_ROOT_INO);
+ s->s_root = d_alloc_root(root_inode, NULL);
+ if (!s->s_root) {
s->s_dev = 0;
brelse(bh);
if (!silent)
@@ -282,11 +281,11 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
return NULL;
}
- errmsg = minix_checkroot(s);
+ errmsg = minix_checkroot(s, root_inode);
if (errmsg) {
if (!silent)
printk("MINIX-fs: %s\n", errmsg);
- iput (s->s_mounted);
+ d_delete(s->s_root); /* XXX Is this enough? */
s->s_dev = 0;
brelse (bh);
MOD_DEC_USE_COUNT;
@@ -307,7 +306,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
return s;
}
-void minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+int minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
@@ -319,7 +318,7 @@ void minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
tmp.f_files = sb->u.minix_sb.s_ninodes;
tmp.f_ffree = minix_count_free_inodes(sb);
tmp.f_namelen = sb->u.minix_sb.s_namelen;
- copy_to_user(buf, &tmp, bufsiz);
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
/*
@@ -472,7 +471,7 @@ repeat:
}
*p = tmp;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return result;
}
@@ -585,7 +584,7 @@ repeat:
}
*p = tmp;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return result;
}
@@ -833,14 +832,12 @@ static struct buffer_head * V1_minix_update_inode(struct inode * inode)
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
- inode->i_dirt = 0;
return 0;
}
block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks +
(ino-1)/MINIX_INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) {
printk("unable to read i-node block\n");
- inode->i_dirt = 0;
return 0;
}
raw_inode = ((struct minix_inode *)bh->b_data) +
@@ -855,7 +852,6 @@ static struct buffer_head * V1_minix_update_inode(struct inode * inode)
raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
else for (block = 0; block < 9; block++)
raw_inode->i_zone[block] = inode->u.minix_i.u.i1_data[block];
- inode->i_dirt=0;
mark_buffer_dirty(bh, 1);
return bh;
}
@@ -874,14 +870,12 @@ static struct buffer_head * V2_minix_update_inode(struct inode * inode)
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
- inode->i_dirt = 0;
return 0;
}
block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks +
(ino-1)/MINIX2_INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) {
printk("unable to read i-node block\n");
- inode->i_dirt = 0;
return 0;
}
raw_inode = ((struct minix2_inode *)bh->b_data) +
@@ -898,7 +892,6 @@ static struct buffer_head * V2_minix_update_inode(struct inode * inode)
raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
else for (block = 0; block < 10; block++)
raw_inode->i_zone[block] = inode->u.minix_i.u.i2_data[block];
- inode->i_dirt=0;
mark_buffer_dirty(bh, 1);
return bh;
}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index b6041ad92..718d3dd07 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -47,9 +47,6 @@ static int minix_match(int len, const char * name,
*offset += info->s_dirsize;
if (!de->inode || len > info->s_namelen)
return 0;
- /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
- if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
- return 1;
return namecompare(len,info->s_namelen,name,de->name);
}
@@ -104,31 +101,22 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
return NULL;
}
-int minix_lookup(struct inode * dir,const char * name, int len,
- struct inode ** result)
+int minix_lookup(struct inode * dir, struct dentry *dentry)
{
- int ino;
+ struct inode * inode = NULL;
struct minix_dir_entry * de;
struct buffer_head * bh;
- *result = NULL;
- if (!dir)
- return -ENOENT;
- if (!S_ISDIR(dir->i_mode)) {
- iput(dir);
- return -ENOENT;
- }
- if (!(bh = minix_find_entry(dir,name,len,&de))) {
- iput(dir);
- return -ENOENT;
- }
- ino = de->inode;
- brelse(bh);
- if (!(*result = iget(dir->i_sb,ino))) {
- iput(dir);
- return -EACCES;
- }
- iput(dir);
+ bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (bh) {
+ unsigned long ino = le32_to_cpu(de->inode);
+ brelse (bh);
+ inode = iget(dir->i_sb, ino);
+
+ if (!inode)
+ return -EACCES;
+ }
+ d_add(dentry, inode);
return 0;
}
@@ -180,7 +168,7 @@ static int minix_add_entry(struct inode * dir,
if (block*bh->b_size + offset > dir->i_size) {
de->inode = 0;
dir->i_size = block*bh->b_size + offset;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
}
if (de->inode) {
if (namecompare(namelen, info->s_namelen, name, de->name)) {
@@ -189,7 +177,7 @@ static int minix_add_entry(struct inode * dir,
}
} else {
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
for (i = 0; i < info->s_namelen ; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
dir->i_version = ++event;
@@ -208,42 +196,37 @@ static int minix_add_entry(struct inode * dir,
return 0;
}
-int minix_create(struct inode * dir,const char * name, int len, int mode,
- struct inode ** result)
+int minix_create(struct inode * dir, struct dentry *dentry, int mode)
{
int error;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
- *result = NULL;
if (!dir)
return -ENOENT;
inode = minix_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
inode->i_op = &minix_file_inode_operations;
inode->i_mode = mode;
- inode->i_dirt = 1;
- error = minix_add_entry(dir,name,len, &bh ,&de);
+ mark_inode_dirty(inode);
+ error = minix_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh ,&de);
if (error) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
- iput(dir);
return error;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- *result = inode;
+ d_instantiate(dentry, inode);
return 0;
}
-int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
+int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
int error;
struct inode * inode;
@@ -252,17 +235,15 @@ int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rd
if (!dir)
return -ENOENT;
- bh = minix_find_entry(dir,name,len,&de);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
brelse(bh);
- iput(dir);
return -EEXIST;
}
inode = minix_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
inode->i_uid = current->fsuid;
inode->i_mode = mode;
inode->i_op = NULL;
@@ -283,24 +264,22 @@ int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rd
init_fifo(inode);
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = to_kdev_t(rdev);
- inode->i_dirt = 1;
- error = minix_add_entry(dir, name, len, &bh, &de);
+ mark_inode_dirty(inode);
+ error = minix_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de);
if (error) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
- iput(dir);
return error;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- iput(inode);
+ d_instantiate(dentry, inode);
return 0;
}
-int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
+int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
{
int error;
struct inode * inode;
@@ -308,33 +287,26 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
struct minix_dir_entry * de;
struct minix_sb_info * info;
- if (!dir || !dir->i_sb) {
- iput(dir);
+ if (!dir || !dir->i_sb)
return -EINVAL;
- }
info = &dir->i_sb->u.minix_sb;
- bh = minix_find_entry(dir,name,len,&de);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
brelse(bh);
- iput(dir);
return -EEXIST;
}
- if (dir->i_nlink >= MINIX_LINK_MAX) {
- iput(dir);
+ if (dir->i_nlink >= MINIX_LINK_MAX)
return -EMLINK;
- }
inode = minix_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
inode->i_op = &minix_dir_inode_operations;
inode->i_size = 2 * info->s_dirsize;
dir_block = minix_bread(inode,0,1);
if (!dir_block) {
- iput(dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -ENOSPC;
}
@@ -350,10 +322,10 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
- inode->i_dirt = 1;
- error = minix_add_entry(dir, name, len, &bh, &de);
+ mark_inode_dirty(inode);
+ error = minix_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
if (error) {
- iput(dir);
inode->i_nlink=0;
iput(inode);
return error;
@@ -361,10 +333,9 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
dir->i_nlink++;
- dir->i_dirt = 1;
- iput(dir);
- iput(inode);
+ mark_inode_dirty(dir);
brelse(bh);
+ d_instantiate(dentry, inode);
return 0;
}
@@ -427,7 +398,7 @@ bad_dir:
return 1;
}
-int minix_rmdir(struct inode * dir, const char * name, int len)
+int minix_rmdir(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
@@ -435,13 +406,14 @@ int minix_rmdir(struct inode * dir, const char * name, int len)
struct minix_dir_entry * de;
inode = NULL;
- bh = minix_find_entry(dir,name,len,&de);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
retval = -ENOENT;
if (!bh)
goto end_rmdir;
retval = -EPERM;
- if (!(inode = iget(dir->i_sb, de->inode)))
- goto end_rmdir;
+ inode = dentry->d_inode;
+
if ((dir->i_mode & S_ISVTX) && !fsuser() &&
current->fsuid != inode->i_uid &&
current->fsuid != dir->i_uid)
@@ -462,7 +434,7 @@ int minix_rmdir(struct inode * dir, const char * name, int len)
retval = -ENOENT;
goto end_rmdir;
}
- if (atomic_read(&inode->i_count) > 1) {
+ if (inode->i_count > 1) {
retval = -EBUSY;
goto end_rmdir;
}
@@ -472,19 +444,18 @@ int minix_rmdir(struct inode * dir, const char * name, int len)
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
inode->i_nlink=0;
- inode->i_dirt=1;
+ mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
- dir->i_dirt=1;
+ mark_inode_dirty(dir);
+ d_delete(dentry);
retval = 0;
end_rmdir:
- iput(dir);
- iput(inode);
brelse(bh);
return retval;
}
-int minix_unlink(struct inode * dir, const char * name, int len)
+int minix_unlink(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
@@ -494,16 +465,16 @@ int minix_unlink(struct inode * dir, const char * name, int len)
repeat:
retval = -ENOENT;
inode = NULL;
- bh = minix_find_entry(dir,name,len,&de);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (!bh)
goto end_unlink;
- if (!(inode = iget(dir->i_sb, de->inode)))
- goto end_unlink;
+ inode = dentry->d_inode;
+
retval = -EPERM;
if (S_ISDIR(inode->i_mode))
goto end_unlink;
if (de->inode != inode->i_ino) {
- iput(inode);
brelse(bh);
current->counter = 0;
schedule();
@@ -527,19 +498,19 @@ repeat:
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
+ d_delete(dentry); /* This also frees the inode */
retval = 0;
end_unlink:
brelse(bh);
- iput(inode);
- iput(dir);
return retval;
}
-int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
+int minix_symlink(struct inode * dir, struct dentry *dentry,
+ const char * symname)
{
struct minix_dir_entry * de;
struct inode * inode = NULL;
@@ -547,17 +518,15 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
int i;
char c;
- if (!(inode = minix_new_inode(dir))) {
- iput(dir);
+ if (!(inode = minix_new_inode(dir)))
return -ENOSPC;
- }
+
inode->i_mode = S_IFLNK | 0777;
inode->i_op = &minix_symlink_inode_operations;
name_block = minix_bread(inode,0,1);
if (!name_block) {
- iput(dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -ENOSPC;
}
@@ -568,93 +537,81 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
mark_buffer_dirty(name_block, 1);
brelse(name_block);
inode->i_size = i;
- inode->i_dirt = 1;
- bh = minix_find_entry(dir,name,len,&de);
+ mark_inode_dirty(inode);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
brelse(bh);
- iput(dir);
return -EEXIST;
}
- i = minix_add_entry(dir, name, len, &bh, &de);
+ i = minix_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
if (i) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
- iput(dir);
return i;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- iput(inode);
+ d_instantiate(dentry, inode);
return 0;
}
-int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
+int minix_link(struct inode * inode, struct inode * dir,
+ struct dentry *dentry)
{
int error;
struct minix_dir_entry * de;
struct buffer_head * bh;
- if (S_ISDIR(oldinode->i_mode)) {
- iput(oldinode);
- iput(dir);
+ if (S_ISDIR(inode->i_mode))
return -EPERM;
- }
- if (oldinode->i_nlink >= MINIX_LINK_MAX) {
- iput(oldinode);
- iput(dir);
+
+ if (inode->i_nlink >= MINIX_LINK_MAX)
return -EMLINK;
- }
- bh = minix_find_entry(dir,name,len,&de);
+
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
brelse(bh);
- iput(dir);
- iput(oldinode);
return -EEXIST;
}
- error = minix_add_entry(dir, name, len, &bh, &de);
+ error = minix_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
if (error) {
- iput(dir);
- iput(oldinode);
+ brelse(bh);
return error;
}
- de->inode = oldinode->i_ino;
+ de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- oldinode->i_nlink++;
- oldinode->i_ctime = CURRENT_TIME;
- oldinode->i_dirt = 1;
- iput(oldinode);
+ inode->i_nlink++;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ d_instantiate(dentry, inode);
return 0;
}
-static int subdir(struct inode * new_inode, struct inode * old_inode)
+static int subdir(struct dentry * new_dentry, struct dentry * old_dentry)
{
- int ino;
- int result;
+ int result = 0;
- atomic_inc(&new_inode->i_count);
- result = 0;
for (;;) {
- if (new_inode == old_inode) {
- result = 1;
- break;
+ if (new_dentry != old_dentry) {
+ struct dentry * parent = new_dentry->d_parent;
+ if (parent == new_dentry)
+ break;
+ new_dentry = parent;
+ continue;
}
- if (new_inode->i_dev != old_inode->i_dev)
- break;
- ino = new_inode->i_ino;
- if (minix_lookup(new_inode,"..",2,&new_inode))
- break;
- if (new_inode->i_ino == ino)
- break;
+ result = 1;
+ break;
}
- iput(new_inode);
return result;
}
@@ -671,8 +628,8 @@ static int subdir(struct inode * new_inode, struct inode * old_inode)
* 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, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len)
+static int do_minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+ struct inode * new_dir, struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -686,28 +643,26 @@ try_again:
brelse(old_bh);
brelse(new_bh);
brelse(dir_bh);
- iput(old_inode);
- iput(new_inode);
current->counter = 0;
schedule();
start_up:
old_inode = new_inode = NULL;
old_bh = new_bh = dir_bh = NULL;
- old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
+ old_bh = minix_find_entry(old_dir, old_dentry->d_name.name,
+ old_dentry->d_name.len, &old_de);
retval = -ENOENT;
if (!old_bh)
goto end_rename;
- old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
- if (!old_inode)
- goto end_rename;
+ old_inode = old_dentry->d_inode;
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
current->fsuid != old_dir->i_uid && !fsuser())
goto end_rename;
- new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
+ new_inode = new_dentry->d_inode;
+ new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
+ new_dentry->d_name.len, &new_de);
if (new_bh) {
- new_inode = __iget(new_dir->i_sb, new_de->inode, 0);
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
@@ -722,13 +677,13 @@ start_up:
if (!S_ISDIR(old_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir(new_dir, old_inode))
+ if (subdir(new_dentry, old_dentry))
goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
retval = -EBUSY;
- if (atomic_read(&new_inode->i_count) > 1)
+ if (new_inode->i_count > 1)
goto end_rename;
}
retval = -EPERM;
@@ -741,7 +696,7 @@ start_up:
if (new_inode && !S_ISDIR(new_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir(new_dir, old_inode))
+ if (subdir(new_dentry, old_dentry))
goto end_rename;
retval = -EIO;
dir_bh = minix_bread(old_inode,0,0);
@@ -754,7 +709,10 @@ start_up:
goto end_rename;
}
if (!new_bh) {
- retval = minix_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
+ retval = minix_add_entry(new_dir,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len,
+ &new_bh, &new_de);
if (retval)
goto end_rename;
}
@@ -769,15 +727,15 @@ start_up:
old_de->inode = 0;
new_de->inode = old_inode->i_ino;
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
- old_dir->i_dirt = 1;
+ mark_inode_dirty(old_dir);
old_dir->i_version = ++event;
new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
- new_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
new_dir->i_version = ++event;
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
}
mark_buffer_dirty(old_bh, 1);
mark_buffer_dirty(new_bh, 1);
@@ -785,24 +743,23 @@ start_up:
PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
mark_buffer_dirty(dir_bh, 1);
old_dir->i_nlink--;
- old_dir->i_dirt = 1;
+ mark_inode_dirty(old_dir);
if (new_inode) {
new_inode->i_nlink--;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
} else {
new_dir->i_nlink++;
- new_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
}
}
+ /* Update the dcache */
+ d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
+ d_delete(new_dentry);
retval = 0;
end_rename:
brelse(dir_bh);
brelse(old_bh);
brelse(new_bh);
- iput(old_inode);
- iput(new_inode);
- iput(old_dir);
- iput(new_dir);
return retval;
}
@@ -815,8 +772,8 @@ end_rename:
* 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, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len)
+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;
@@ -825,8 +782,8 @@ int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
while (lock)
sleep_on(&wait);
lock = 1;
- result = do_minix_rename(old_dir, old_name, old_len,
- new_dir, new_name, new_len);
+ result = do_minix_rename(old_dir, old_dentry,
+ new_dir, new_dentry);
lock = 0;
wake_up(&wait);
return result;
diff --git a/fs/minix/symlink.c b/fs/minix/symlink.c
index 92539cded..9f759ecc9 100644
--- a/fs/minix/symlink.c
+++ b/fs/minix/symlink.c
@@ -15,6 +15,7 @@
#include <asm/uaccess.h>
static int minix_readlink(struct inode *, char *, int);
+static struct dentry *minix_follow_link(struct inode *, struct dentry *);
/*
* symlinks can't do much...
@@ -31,6 +32,7 @@ struct inode_operations minix_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
minix_readlink, /* readlink */
+ minix_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -38,6 +40,21 @@ struct inode_operations minix_symlink_inode_operations = {
NULL /* permission */
};
+static struct dentry * minix_follow_link(struct inode * inode, struct dentry * base)
+{
+ struct buffer_head * bh;
+
+ bh = minix_bread(inode, 0, 0);
+ if (!bh) {
+ dput(base);
+ return ERR_PTR(-EIO);
+ }
+ UPDATE_ATIME(inode);
+ base = lookup_dentry(bh->b_data, base, 1);
+ brelse(bh);
+ return base;
+}
+
static int minix_readlink(struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh;
@@ -47,7 +64,6 @@ static int minix_readlink(struct inode * inode, char * buffer, int buflen)
if (buflen > 1023)
buflen = 1023;
bh = minix_bread(inode, 0, 0);
- iput(inode);
if (!bh)
return 0;
i = 0;
diff --git a/fs/minix/truncate.c b/fs/minix/truncate.c
index a6d3d4b5e..298d6c155 100644
--- a/fs/minix/truncate.c
+++ b/fs/minix/truncate.c
@@ -58,7 +58,7 @@ repeat:
continue;
}
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
if (bh) {
mark_buffer_clean(bh);
brelse(bh);
@@ -167,7 +167,7 @@ repeat:
else {
tmp = *p;
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
@@ -191,7 +191,7 @@ void V1_minix_truncate(struct inode * inode)
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
/*
@@ -220,7 +220,7 @@ repeat:
continue;
}
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
if (bh) {
mark_buffer_clean(bh);
brelse(bh);
@@ -329,7 +329,7 @@ repeat:
else {
tmp = *p;
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
@@ -374,7 +374,7 @@ repeat:
else {
tmp = *p;
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
brelse(tind_bh);
@@ -402,7 +402,7 @@ static void V2_minix_truncate(struct inode * inode)
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
/*
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index bcf6782d0..9481a763c 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -280,7 +280,7 @@ static int msdos_create_entry(struct inode *dir, const char *name,int len,
* XXX all times should be set by caller upon successful completion.
*/
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
memcpy(de->name,name,MSDOS_NAME);
memset(de->unused, 0, sizeof(de->unused));
de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
@@ -295,7 +295,7 @@ static int msdos_create_entry(struct inode *dir, const char *name,int len,
if (!*result) return -EIO;
(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
CURRENT_TIME;
- (*result)->i_dirt = 1;
+ mark_inode_dirty(*result);
return 0;
}
@@ -369,7 +369,7 @@ static int msdos_empty(struct inode *dir)
struct buffer_head *bh;
struct msdos_dir_entry *de;
- if (atomic_read(&dir->i_count) > 1)
+ if (dir->i_count > 1)
return -EBUSY;
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
@@ -415,7 +415,8 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
inode->i_nlink = 0;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
- inode->i_dirt = dir->i_dirt = 1;
+ mark_inode_dirty(inode);
+ mark_inode_dirty(dir);
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
res = 0;
@@ -465,7 +466,7 @@ int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
dot->i_nlink = inode->i_nlink;
- dot->i_dirt = 1;
+ mark_inode_dirty(dot);
iput(dot);
if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,2,1,0,&dot)) < 0)
goto mkdir_error;
@@ -473,7 +474,7 @@ int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
dot->i_size = dir->i_size;
MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
dot->i_nlink = dir->i_nlink;
- dot->i_dirt = 1;
+ mark_inode_dirty(dot);
MSDOS_I(inode)->i_busy = 0;
iput(dot);
iput(inode);
@@ -519,7 +520,8 @@ static int msdos_unlinkx(
inode->i_nlink = 0;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
MSDOS_I(inode)->i_busy = 1;
- inode->i_dirt = dir->i_dirt = 1;
+ mark_inode_dirty(inode);
+ mark_inode_dirty(dir);
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
unlink_done:
@@ -580,11 +582,11 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,int old_len,
}
if (S_ISDIR(new_inode->i_mode)) {
new_dir->i_nlink--;
- new_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
}
new_inode->i_nlink = 0;
MSDOS_I(new_inode)->i_busy = 1;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
new_de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, new_bh, 1);
iput(new_inode);
@@ -675,7 +677,7 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
}
new_inode->i_nlink = 0;
MSDOS_I(new_inode)->i_busy = 1;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
new_de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, new_bh, 1);
}
@@ -696,14 +698,14 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
}
if (exists && S_ISDIR(new_inode->i_mode)) {
new_dir->i_nlink--;
- new_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
}
msdos_read_inode(free_inode);
MSDOS_I(old_inode)->i_busy = 1;
MSDOS_I(old_inode)->i_linked = free_inode;
MSDOS_I(free_inode)->i_oldlink = old_inode;
fat_cache_inval_inode(old_inode);
- old_inode->i_dirt = 1;
+ mark_inode_dirty(old_inode);
old_de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, old_bh, 1);
fat_mark_buffer_dirty(sb, free_bh, 1);
@@ -711,7 +713,7 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
MSDOS_I(new_inode)->i_depend = free_inode;
MSDOS_I(free_inode)->i_old = new_inode;
/* Two references now exist to free_inode so increase count */
- atomic_inc(&free_inode->i_count);
+ free_inode->i_count++;
/* free_inode is put after putting new_inode and old_inode */
iput(new_inode);
fat_brelse(sb, new_bh);
@@ -726,7 +728,7 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
}
dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
MSDOS_I(new_dir)->i_start;
- dotdot_inode->i_dirt = 1;
+ mark_inode_dirty(dotdot_inode);
fat_mark_buffer_dirty(sb, dotdot_bh, 1);
old_dir->i_nlink--;
new_dir->i_nlink++;
@@ -793,6 +795,7 @@ struct inode_operations msdos_dir_inode_operations = {
NULL, /* mknod */
msdos_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
diff --git a/fs/namei.c b/fs/namei.c
index 198179b98..2ec173f0d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -12,7 +12,6 @@
* lookup logic.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -20,10 +19,7 @@
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/mm.h>
-#include <linux/dalloc.h>
-#include <linux/nametrans.h>
#include <linux/proc_fs.h>
-#include <linux/omirr.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -37,10 +33,6 @@
#undef DEBUG /* some other debugging */
-/* local flags for __namei() */
-#define NAM_SEMLOCK 8 /* set a semlock on the last dir */
-#define NAM_TRANSCREATE 16 /* last component may be created, try "=CREATE#" suffix*/
-#define NAM_NO_TRAILSLASH 32 /* disallow trailing slashes by returning EISDIR */
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
/* [Feb-1997 T. Schoebel-Theuer]
@@ -56,7 +48,7 @@
* is done solely in the VFS level, such that <fs>_follow_link() is not
* used any more and could be removed in future. As a side effect,
* dir_namei(), _namei() and follow_link() are now replaced with a single
- * function __namei() that can handle all the special cases of the former
+ * function lookup_dentry() that can handle all the special cases of the former
* code.
*
* With the new dcache, the pathname is stored at each inode, at least as
@@ -95,13 +87,13 @@ static inline char * get_page(void)
char * res;
down(&quicklock);
res = quicklist;
- if(res) {
+ if (res) {
#ifdef DEBUG
char * tmp = res;
int i;
for(i=0; i<quickcount; i++)
tmp = *(char**)tmp;
- if(tmp)
+ if (tmp)
printk("bad quicklist %x\n", (int)tmp);
#endif
quicklist = *(char**)res;
@@ -113,9 +105,21 @@ static inline char * get_page(void)
return res;
}
+/*
+ * Kernel pointers have redundant information, so we can use a
+ * scheme where we can return either an error code or a dentry
+ * pointer with the same return value.
+ *
+ * This should be a per-architecture thing, to allow different
+ * error and pointer decisions.
+ */
+#define ERR_PTR(err) ((void *)((long)(err)))
+#define PTR_ERR(ptr) ((long)(ptr))
+#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000))
+
inline void putname(char * name)
{
- if(name) {
+ if (name) {
down(&quicklock);
*(char**)name = quicklist;
quicklist = name;
@@ -154,20 +158,22 @@ static inline int do_getname(const char *filename, char *page)
return retval;
}
-int getname(const char * filename, char **result)
+char * getname(const char * filename)
{
- char *tmp;
- int retval;
+ char *tmp, *result;
+ result = ERR_PTR(-ENOMEM);
tmp = get_page();
- if(!tmp)
- return -ENOMEM;
- retval = do_getname(filename, tmp);
- if (retval < 0)
- putname(tmp);
- else
- *result = tmp;
- return retval;
+ if (tmp) {
+ int retval = do_getname(filename, tmp);
+
+ result = tmp;
+ if (retval < 0) {
+ putname(tmp);
+ result = ERR_PTR(retval);
+ }
+ }
+ return result;
}
/*
@@ -222,417 +228,207 @@ void put_write_access(struct inode * inode)
inode->i_writecount--;
}
-static /*inline */ int concat(struct qstr * name, struct qstr * appendix, char * buf)
+/*
+ * This is called when everything else fails, and we actually have
+ * to go to the low-level filesystem to find out what we should do..
+ *
+ * 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)
{
- int totallen = name->len;
- if(name->len > MAX_TRANS_FILELEN ||
- appendix->len > MAX_TRANS_SUFFIX) {
- return -ENAMETOOLONG;
+ struct dentry * result;
+ struct inode *dir = parent->d_inode;
+
+ result = ERR_PTR(-ENOTDIR);
+ if (dir->i_op && dir->i_op->lookup) {
+ down(&dir->i_sem);
+ result = d_lookup(parent, name);
+ if (!result) {
+ int error;
+ result = d_alloc(parent, name);
+ error = dir->i_op->lookup(dir, result);
+ if (error) {
+ d_free(result);
+ result = ERR_PTR(error);
+ }
+ }
+ up(&dir->i_sem);
}
- memcpy(buf, name->name, name->len);
- memcpy(buf + name->len, appendix->name, appendix->len);
- totallen += appendix->len;
- buf[totallen] = '\0';
- return totallen;
+ return result;
}
-/* Internal lookup() using the new generic dcache.
- * buf must only be supplied if appendix!=NULL.
- */
-static int cached_lookup(struct inode * dir, struct qstr * name,
- struct qstr * appendix, char * buf,
- struct qstr * res_name, struct dentry ** res_entry,
- struct inode ** result)
+/* Internal lookup() using the new generic dcache. */
+static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
{
- struct qstr tmp = { name->name, name->len };
- int error;
- struct dentry * cached;
-
- *result = NULL;
- if(name->len >= D_MAXLEN)
- return -ENAMETOOLONG;
- vfs_lock();
- cached = d_lookup(dir, name, appendix);
- if(cached) {
- struct inode *inode = NULL;
+ struct dentry * dentry = d_lookup(parent, name);
- if(cached->u.d_inode && (inode = d_inode(&cached))) {
- error = 0;
- if(appendix && res_name) {
- tmp.len = error = concat(name, appendix, buf);
- tmp.name = buf;
- if(error > 0)
- error = 0;
- }
- } else {
- error = -ENOENT;
+ if (dentry) {
+ if (dentry->d_revalidate) {
+ /* spin_unlock(&dentry_lock); */
+ dentry = dentry->d_revalidate(dentry);
+ /* spin_lock(&dentry_lock); */
}
- vfs_unlock();
- if(res_entry)
- *res_entry = cached;
- /* Since we are bypassing the iget() mechanism, we have to
- * fabricate the act of crossing any mount points.
+ /*
+ * The parent d_count _should_ be at least 2: one for the
+ * dentry we found, and one for the fact that we are using
+ * it.
*/
- if(!error && inode && inode->i_mount) {
- do {
- struct inode *mnti = inode->i_mount;
- iinc(mnti);
- iput(inode);
- inode = mnti;
- } while(inode->i_mount);
+ if (parent->d_count <= 1) {
+ printk("lookup of %s success in %s, but parent count is %d\n",
+ dentry->d_name.name, parent->d_name.name, parent->d_count);
}
- *result = inode;
- goto done;
- } else
- vfs_unlock();
-
- if(appendix) {
- tmp.len = error = concat(name, appendix, buf);
- tmp.name = buf;
- if(error < 0)
- goto done;
- }
- atomic_inc(&dir->i_count);
- error = dir->i_op->lookup(dir, tmp.name, tmp.len, result);
- if(dir->i_dentry && tmp.len &&
- (!error || (error == -ENOENT && (!dir->i_sb || !dir->i_sb->s_type ||
- !(dir->i_sb->s_type->fs_flags & FS_NO_DCACHE))))) {
- struct dentry * res;
- vfs_lock();
- res = d_entry(dir->i_dentry, &tmp, error ? NULL : *result);
- vfs_unlock();
- if(res_entry)
- *res_entry = res;
}
-done:
- if(res_name) {
- if(error) {
- res_name->name = name->name;
- res_name->len = name->len;
- } else {
- res_name->name = tmp.name;
- res_name->len = tmp.len;
- }
- }
- return error;
+ return dentry;
}
-#ifdef CONFIG_TRANS_NAMES
-/* If a normal filename is seen, try to determine whether a
- * "#keyword=context#" file exists and return the new filename.
- * If the name is to be created (create_mode), check whether a
- * "#keyword=CREATE" name exists and optionally return the corresponding
- * context name even if it didn't exist before.
+/*
+ * "." and ".." are special - ".." especially so because it has to be able
+ * to know about the current root directory and parent relationships
*/
-static int check_suffixes(struct inode * dir, struct qstr * name,
- int create_mode, char * buf,
- struct qstr * res_name, struct dentry ** res_entry,
- struct inode ** result)
+static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * name)
{
- struct translations * trans;
- char * env;
- struct qstr * suffixes;
- int i;
- int error = -ENOENT;
-
- if(!buf)
- panic("buf==NULL");
- env = env_transl();
-#ifdef CONFIG_TRANS_RESTRICT
- if(!env && dir->i_gid != CONFIG_TRANS_GID) {
- return error;
- }
-#endif
- trans = get_translations(env);
- suffixes = create_mode ? trans->c_name : trans->name;
- for(i = 0; i < trans->count; i++) {
- error = cached_lookup(dir, name, &suffixes[i],
- buf, res_name, res_entry, result);
- if(!error) {
- if(res_name && create_mode) {
- /* buf == res_name->name, but is writable */
- memcpy(buf + name->len,
- trans->name[i].name,
- trans->name[i].len);
- res_name->len = name->len + trans->name[i].len;
- buf[res_name->len] = '\0';
- }
+ struct dentry *result = NULL;
+ if (name->name[0] == '.') {
+ switch (name->len) {
+ default:
break;
+ case 2:
+ if (name->name[1] != '.')
+ break;
+
+ if (parent != current->fs->root)
+ parent = parent->d_covers->d_parent;
+ /* fallthrough */
+ case 1:
+ result = parent;
}
}
- if(env)
- free_page((unsigned long)trans);
- return error;
-}
-
-#endif
-
-/* Any operations involving reserved names at the VFS level should go here. */
-static /*inline*/ int reserved_lookup(struct inode * dir, struct qstr * name,
- int create_mode, char * buf,
- struct inode ** result)
-{
- int error = -ENOENT;
- if(name->name[0] == '.') {
- if(name->len == 1) {
- *result = dir;
- error = 0;
- } else if (name->len==2 && name->name[1] == '.') {
- if (dir == current->fs->root) {
- *result = dir;
- error = 0;
- }
- else if(dir->i_dentry) {
- error = 0;
- *result = dir->i_dentry->d_parent->u.d_inode;
- if(!*result) {
- printk("dcache parent directory is lost");
- error = -ESTALE; /* random error */
- }
- }
- }
- if(!error)
- atomic_inc(&(*result)->i_count);
- }
- return error;
+ return result;
}
/* In difference to the former version, lookup() no longer eats the dir. */
-static /*inline*/ int lookup(struct inode * dir, struct qstr * name, int create_mode,
- char * buf, struct qstr * res_name,
- struct dentry ** res_entry, struct inode ** result)
+static struct dentry * lookup(struct dentry * dir, struct qstr * name)
{
- int perm;
-
- *result = NULL;
- perm = -ENOENT;
- if (!dir)
- goto done;
+ int err;
+ struct dentry * result;
/* Check permissions before traversing mount-points. */
- perm = permission(dir,MAY_EXEC);
- if (perm)
- goto done;
- perm = reserved_lookup(dir, name, create_mode, buf, result);
- if(!perm) {
- if(res_name) {
- res_name->name = name->name;
- res_name->len = name->len;
- }
- goto done;
- }
- perm = -ENOTDIR;
- if (!dir->i_op || !dir->i_op->lookup)
- goto done;
-#ifdef CONFIG_TRANS_NAMES /* try suffixes */
- perm = check_suffixes(dir, name, 0, buf, res_name, res_entry, result);
- if(perm) /* try original name */
-#endif
- perm = cached_lookup(dir, name, NULL, buf, res_name, res_entry, result);
-#ifdef CONFIG_TRANS_NAMES
- if(perm == -ENOENT && create_mode) { /* try the =CREATE# suffix */
- struct inode * dummy;
- if(!check_suffixes(dir, name, 1, buf, res_name, NULL, &dummy)) {
- iput(dummy);
- }
+ err = permission(dir->d_inode, MAY_EXEC);
+ result = ERR_PTR(err);
+ if (err)
+ goto done_error;
+
+ result = reserved_lookup(dir, name);
+ if (result)
+ goto done_noerror;
+
+ result = cached_lookup(dir, name);
+ if (result)
+ goto done_noerror;
+
+ result = real_lookup(dir, name);
+
+ if (!IS_ERR(result)) {
+done_noerror:
+ result = dget(result->d_mounts);
}
-#endif
-done:
- return perm;
+done_error:
+ return result;
}
-/* [8-Feb-97 T. Schoebel-Theuer] follow_link() modified for generic operation
- * on the VFS layer: first call <fs>_readlink() and then open_namei().
- * All <fs>_follow_link() are not used any more and may be eliminated
- * (by Linus; I refrained in order to not break other patches).
- * Single exeption is procfs, where proc_follow_link() is used
- * internally (and perhaps should be rewritten).
- * Note: [partly obsolete] I removed parameters flag and mode, since now
- * __namei() is called instead of open_namei(). In the old semantics,
- * the _last_ instance of open_namei() did the real create() if O_CREAT was
- * set and the name existed already in form of a symlink. This has been
- * simplified now, and also the semantics when combined with O_EXCL has changed.
- ****************************************************************************
- * [13-Feb-97] Complete rewrite -> functionality of reading symlinks factored
- * out into _read_link(). The above notes remain valid in principle.
+/*
+ * This should check "link_count", but doesn't do that yet..
*/
-static /*inline*/ int _read_link(struct inode * inode, char ** linkname, int loopcount)
+static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry)
{
- unsigned long old_fs;
- int error;
+ struct inode * inode = dentry->d_inode;
- error = -ENOSYS;
- if (!inode->i_op || !inode->i_op->readlink)
- goto done;
- error = -ELOOP;
- if (current->link_count + loopcount > 10)
- goto done;
- error = -ENOMEM;
- if(!*linkname && !(*linkname = get_page()))
- goto done;
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
- atomic_inc(&inode->i_count);
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- error = inode->i_op->readlink(inode, *linkname, PAGE_SIZE);
- set_fs(old_fs);
- if(!error) {
- error = -ENOENT; /* ? or other error code ? */
- } else if(error > 0) {
- (*linkname)[error] = '\0';
- error = 0;
+ if (inode && inode->i_op && inode->i_op->follow_link) {
+ struct dentry *result;
+
+ /* This eats the base */
+ result = inode->i_op->follow_link(inode, base);
+ base = dentry;
+ dentry = result;
}
-done:
- iput(inode);
- return error;
+ dput(base);
+ return dentry;
}
-/* [13-Feb-97 T. Schoebel-Theuer] complete rewrite:
- * merged dir_name(), _namei() and follow_link() into one new routine
- * that obeys all the special cases hidden in the old routines in a
- * (hopefully) systematic way:
- * parameter retrieve_mode is bitwise or'ed of the ST_* flags.
- * if res_inode is a NULL pointer, dont try to retrieve the last component
- * at all. Parameters with prefix last_ are used only if res_inode is
- * non-NULL and refer to the last component of the path only.
+/*
+ * Name resolution.
+ *
+ * This is the basic name resolution function, turning a pathname
+ * into the final dentry.
*/
-int __namei(int retrieve_mode, const char * name, struct inode * base,
- char * buf, struct inode ** res_dir, struct inode ** res_inode,
- struct qstr * last_name, struct dentry ** last_entry,
- int * last_error)
+struct dentry * lookup_dentry(const char * name, struct dentry * base, int follow_link)
{
- char c;
- struct qstr this;
- char * linkname = NULL;
- char * oldlinkname = NULL;
- int trail_flag = 0;
- int loopcount = 0;
- int error;
-#ifdef DEBUG
- if(last_name) {
- last_name->name = "(Uninitialized)";
- last_name->len = 15;
- }
-#endif
-again:
- error = -ENOENT;
- this.name = name;
- if (this.name[0] == '/') {
- if(base)
- iput(base);
- if (__prefix_namei(retrieve_mode, this.name, base, buf,
- res_dir, res_inode,
- last_name, last_entry, last_error) == 0)
- return 0;
- base = current->fs->root;
- atomic_inc(&base->i_count);
- this.name++;
+ struct dentry * dentry;
+
+ if (*name == '/') {
+ if (base)
+ dput(base);
+ base = dget(current->fs->root);
+ do {
+ name++;
+ } while (*name == '/');
} else if (!base) {
- base = current->fs->pwd;
- atomic_inc(&base->i_count);
+ base = dget(current->fs->pwd);
}
+
+ if (!*name)
+ goto return_base;
+
+ /* At this point we know we have a real path component. */
for(;;) {
- struct inode * inode;
- const char * tmp = this.name;
int len;
+ unsigned long hash;
+ struct qstr this;
+ char c, follow;
- for(len = 0; (c = *tmp++) && (c != '/'); len++) ;
- this.len = len;
- if(!c)
+ dentry = ERR_PTR(-ENOENT);
+ if (!base->d_inode)
break;
- while((c = *tmp) == '/') /* remove embedded/trailing slashes */
- tmp++;
- if(!c) {
- trail_flag = 1;
- if(retrieve_mode & NAM_NO_TRAILSLASH) {
- error = -EISDIR;
- goto alldone;
- }
- break;
- }
-#if 0
- if(atomic_read(&base->i_count) == 0)
- printk("vor lookup this=%s tmp=%s\n", this.name, tmp);
-#endif
- error = lookup(base, &this, 0, buf, NULL, NULL, &inode);
-#if 0
- if(atomic_read(&base->i_count) == 0)
- printk("nach lookup this=%s tmp=%s\n", this.name, tmp);
-#endif
- if (error)
- goto alldone;
- if(S_ISLNK(inode->i_mode)) {
- error = _read_link(inode, &linkname, loopcount);
- if(error)
- goto alldone;
- current->link_count++;
- error = __namei((retrieve_mode &
- ~(NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH))
- | NAM_FOLLOW_LINK,
- linkname, base, buf,
- &base, &inode, NULL, NULL, NULL);
- current->link_count--;
- if(error)
- goto alldone;
- }
-#if 0
- if(atomic_read(&base->i_count) == 0)
- printk("this=%s tmp=%s\n", this.name, tmp);
-#endif
- this.name = tmp;
- iput(base);
- base = inode;
- }
- if(res_inode) {
- if(retrieve_mode & NAM_SEMLOCK)
- down(&base->i_sem);
- error = lookup(base, &this, retrieve_mode & NAM_TRANSCREATE,
- buf, last_name, last_entry, res_inode);
- if(!error && S_ISLNK((*res_inode)->i_mode) &&
- ((retrieve_mode & NAM_FOLLOW_LINK) ||
- (trail_flag && (retrieve_mode & NAM_FOLLOW_TRAILSLASH)))) {
- char * tmp;
-
- error = _read_link(*res_inode, &linkname, loopcount);
- if(error)
- goto lastdone;
- if(retrieve_mode & NAM_SEMLOCK)
- up(&base->i_sem);
- /* exchange pages */
- name = tmp = linkname;
- linkname = oldlinkname; oldlinkname = tmp;
- loopcount++;
- goto again; /* Tail recursion elimination "by hand",
- * uses less dynamic memory.
- */
-
- /* Note that trail_flag is not reset, so it
- * does not matter in a symlink chain where a
- * trailing slash indicates a directory endpoint.
- */
- }
- if(!error && trail_flag && !S_ISDIR((*res_inode)->i_mode)) {
- iput(*res_inode);
- error = -ENOTDIR;
- }
- lastdone:
- if(last_error) {
- *last_error = error;
- error = 0;
+ this.name = name;
+ hash = init_name_hash();
+ len = 0;
+ c = *name;
+ do {
+ len++; name++;
+ hash = partial_name_hash(c, hash);
+ c = *name;
+ } while (c && (c != '/'));
+
+ this.len = len;
+ this.hash = end_name_hash(hash);
+
+ /* remove trailing slashes? */
+ follow = follow_link;
+ if (c) {
+ follow |= c;
+ do {
+ c = *++name;
+ } while (c == '/');
}
+
+ dentry = lookup(base, &this);
+ if (IS_ERR(dentry))
+ break;
+
+ if (!follow)
+ break;
+
+ base = do_follow_link(base, dentry);
+ if (c && !IS_ERR(base))
+ continue;
+
+return_base:
+ return base;
}
-alldone:
- if(!error && res_dir)
- *res_dir = base;
- else
- iput(base);
- putname(linkname);
- putname(oldlinkname);
- return error;
+ dput(base);
+ return dentry;
}
/*
@@ -641,24 +437,41 @@ alldone:
* is used by most simple commands to get the inode of a specified name.
* Open, link etc use their own routines, but this is enough for things
* like 'chmod' etc.
+ *
+ * namei exists in two versions: namei/lnamei. The only difference is
+ * that namei follows links, while lnamei does not.
*/
+struct dentry * __namei(const char *pathname, int follow_link)
+{
+ char *name;
+ struct dentry *dentry;
+
+ name = getname(pathname);
+ dentry = (struct dentry *) name;
+ if (!IS_ERR(name)) {
+ dentry = lookup_dentry(name, NULL, follow_link);
+ putname(name);
+ if (!IS_ERR(dentry)) {
+ if (!dentry->d_inode) {
+ dput(dentry);
+ dentry = ERR_PTR(-ENOENT);
+ }
+ }
+ }
+ return dentry;
+}
-/* [Feb 1997 T.Schoebel-Theuer] lnamei() completely removed; can be
- * simulated when calling with retrieve_mode==NAM_FOLLOW_TRAILSLASH.
- */
-int namei(int retrieve_mode, const char *pathname, struct inode **res_inode)
+static inline struct inode *get_parent(struct dentry *dentry)
{
- int error;
- char * tmp;
+ return dentry->d_parent->d_inode;
+}
- error = getname(pathname, &tmp);
- if (!error) {
- char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- error = __namei(retrieve_mode, tmp, NULL,
- buf, NULL, res_inode, NULL, NULL, NULL);
- putname(tmp);
- }
- return error;
+static inline struct inode *lock_parent(struct dentry *dentry)
+{
+ struct inode *dir = dentry->d_parent->d_inode;
+
+ down(&dir->i_sem);
+ return dir;
}
/*
@@ -674,175 +487,157 @@ int namei(int retrieve_mode, const char *pathname, struct inode **res_inode)
* which is a lot more logical, and also allows the "no perm" needed
* for symlinks (where the permissions are checked later).
*/
-int open_namei(const char * pathname, int flag, int mode,
- struct inode ** res_inode, struct inode * base)
+struct dentry * open_namei(const char * pathname, int flag, int mode)
{
- char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- struct qstr last;
- int error;
- int lasterror;
- struct inode * dir, * inode;
- int namei_mode;
+ int acc_mode, error;
+ struct inode *inode;
+ struct dentry *dentry;
mode &= S_IALLUGO & ~current->fs->umask;
mode |= S_IFREG;
- namei_mode = NAM_FOLLOW_LINK;
- if(flag & O_CREAT)
- namei_mode |= NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH;
- error = __namei(namei_mode, pathname, base, buf,
- &dir, &inode, &last, NULL, &lasterror);
- if (error)
- goto exit;
- error = lasterror;
+ dentry = lookup_dentry(pathname, NULL, 1);
+ if (IS_ERR(dentry))
+ return dentry;
+
+ acc_mode = ACC_MODE(flag);
if (flag & O_CREAT) {
- if (!error) {
- if (flag & O_EXCL) {
+ struct inode *dir;
+
+ dir = lock_parent(dentry);
+ /*
+ * The existence test must be done _after_ getting the directory
+ * semaphore - the dentry might otherwise change.
+ */
+ if (dentry->d_inode) {
+ error = 0;
+ if (flag & O_EXCL)
error = -EEXIST;
- }
} else if (IS_RDONLY(dir))
error = -EROFS;
else if (!dir->i_op || !dir->i_op->create)
error = -EACCES;
- else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
- ; /* error is already set! */
- else {
- d_del(d_lookup(dir, &last, NULL), D_REMOVE);
- atomic_inc(&dir->i_count); /* create eats the dir */
+ else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) == 0) {
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
- error = dir->i_op->create(dir, last.name, last.len,
- mode, res_inode);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_print(dir->i_dentry, NULL, &last,
- " c %ld %d ", CURRENT_TIME, mode);
-#endif
- up(&dir->i_sem);
- goto exit_dir;
+ error = dir->i_op->create(dir, dentry, mode);
+ /* Don't check for write permission */
+ acc_mode = 0;
}
up(&dir->i_sem);
+ if (error)
+ goto exit;
}
+
+ error = -ENOENT;
+ inode = dentry->d_inode;
+ if (!inode)
+ goto exit;
+
+ error = -EISDIR;
+ if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
+ goto exit;
+
+ error = permission(inode,acc_mode);
if (error)
- goto exit_inode;
+ goto exit;
- if (S_ISDIR(inode->i_mode) && (flag & 2)) {
- error = -EISDIR;
- goto exit_inode;
- }
- if ((error = permission(inode,ACC_MODE(flag))) != 0) {
- goto exit_inode;
- }
+ /*
+ * FIFO's, sockets and device files are special: they don't
+ * actually live on the filesystem itself, and as such you
+ * can write to them even if the filesystem is read-only.
+ */
if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
- /*
- * 2-Feb-1995 Bruce Perens <Bruce@Pixar.com>
- * Allow opens of Unix domain sockets and FIFOs for write on
- * read-only filesystems. Their data does not live on the disk.
- *
- * If there was something like IS_NODEV(inode) for
- * pipes and/or sockets I'd check it here.
- */
flag &= ~O_TRUNC;
- }
- else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
- if (IS_NODEV(inode)) {
- error = -EACCES;
- goto exit_inode;
- }
+ } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
+ error = -EACCES;
+ if (IS_NODEV(inode))
+ goto exit;
+
flag &= ~O_TRUNC;
} else {
- if (IS_RDONLY(inode) && (flag & 2)) {
- error = -EROFS;
- goto exit_inode;
- }
+ error = -EROFS;
+ if (IS_RDONLY(inode) && (flag & 2))
+ goto exit;
}
/*
* An append-only file must be opened in append mode for writing.
*/
- if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND))) {
- error = -EPERM;
- goto exit_inode;
- }
+ error = -EPERM;
+ if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND)))
+ goto exit;
+
if (flag & O_TRUNC) {
- if ((error = get_write_access(inode)))
- goto exit_inode;
+ error = get_write_access(inode);
+ if (error)
+ goto exit;
+
/*
* Refuse to truncate files with mandatory locks held on them.
*/
error = locks_verify_locked(inode);
- if (error)
- goto exit_inode;
- if (inode->i_sb && inode->i_sb->dq_op)
- inode->i_sb->dq_op->initialize(inode, -1);
+ if (!error) {
+ if (inode->i_sb && inode->i_sb->dq_op)
+ inode->i_sb->dq_op->initialize(inode, -1);
- error = do_truncate(inode, 0);
+ error = do_truncate(inode, 0);
+ }
put_write_access(inode);
+ if (error)
+ goto exit;
} else
if (flag & FMODE_WRITE)
if (inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize(inode, -1);
-exit_inode:
- if(error) {
- if(!lasterror)
- iput(inode);
- } else
- *res_inode = inode;
-exit_dir:
- iput(dir);
+
+ return dentry;
+
exit:
- return error;
+ dput(dentry);
+ return ERR_PTR(error);
}
-int do_mknod(const char * filename, int mode, dev_t dev)
+struct dentry * do_mknod(const char * filename, int mode, dev_t dev)
{
- char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- struct qstr last;
- int error, lasterror;
- struct inode * dir;
- struct inode * inode;
+ int error;
+ struct inode *dir;
+ struct dentry *dentry, *retval;
mode &= ~current->fs->umask;
- error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH,
- filename, NULL, buf,
- &dir, &inode, &last, NULL, &lasterror);
+ dentry = lookup_dentry(filename, NULL, 1);
+ if (IS_ERR(dentry))
+ return dentry;
+
+ dir = lock_parent(dentry);
+
+ retval = ERR_PTR(-EEXIST);
+ if (dentry->d_inode)
+ goto exit_lock;
+
+ retval = ERR_PTR(-EROFS);
+ if (IS_RDONLY(dir))
+ goto exit_lock;
+
+ error = permission(dir,MAY_WRITE | MAY_EXEC);
+ retval = ERR_PTR(error);
if (error)
- goto exit;
- if(!lasterror) {
- error = -EEXIST;
- goto exit_inode;
- }
- if (!last.len) {
- error = -ENOENT;
- goto exit_inode;
- }
- if (IS_RDONLY(dir)) {
- error = -EROFS;
- goto exit_inode;
- }
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
- goto exit_inode;
- if (!dir->i_op || !dir->i_op->mknod) {
- error = -ENOSYS; /* instead of EPERM, what does Posix say? */
- goto exit_inode;
- }
- atomic_inc(&dir->i_count);
+ goto exit_lock;
+
+ retval = ERR_PTR(-EPERM);
+ if (!dir->i_op || !dir->i_op->mknod)
+ goto exit_lock;
+
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
- down(&dir->i_sem);
- d_del(d_lookup(dir, &last, NULL), D_REMOVE);
- error = dir->i_op->mknod(dir, last.name, last.len, mode, dev);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_print(dir->i_dentry, NULL, &last, " n %ld %d %d ",
- CURRENT_TIME, mode, dev);
-#endif
+ error = dir->i_op->mknod(dir, dentry, mode, dev);
+ retval = ERR_PTR(error);
+ if (!error)
+ retval = dget(dentry);
+
+exit_lock:
up(&dir->i_sem);
-exit_inode:
- if(!lasterror)
- iput(inode);
- iput(dir);
-exit:
- return error;
+ dput(dentry);
+ return retval;
}
asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
@@ -864,68 +659,63 @@ asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
default:
goto out;
}
- error = getname(filename,&tmp);
- if (!error) {
- error = do_mknod(tmp,mode,dev);
+ tmp = getname(filename);
+ error = PTR_ERR(tmp);
+ if (!IS_ERR(tmp)) {
+ struct dentry * dentry = do_mknod(tmp,mode,dev);
putname(tmp);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ dput(dentry);
+ error = 0;
+ }
}
out:
unlock_kernel();
return error;
}
-/* [Feb-97 T. Schoebel-Theuer] remove_trailing_slashes() is now obsolete,
- * its functionality is handled by observing trailing slashes in __namei().
+/*
+ * Look out: this function may change a normal dentry
+ * into a directory dentry (different size)..
*/
static inline int do_mkdir(const char * pathname, int mode)
{
- char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- struct qstr last;
- int error, lasterror;
- struct inode * dir;
- struct inode * inode;
+ int error;
+ struct inode *dir;
+ struct dentry *dentry;
- mode &= 0777 & ~current->fs->umask;
+ dentry = lookup_dentry(pathname, NULL, 1);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto exit;
+
+ dir = lock_parent(dentry);
+
+ error = -EEXIST;
+ if (dentry->d_inode)
+ goto exit_lock;
+
+ error = -EROFS;
+ if (IS_RDONLY(dir))
+ goto exit_lock;
- error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, pathname, NULL, buf,
- &dir, &inode, &last, NULL, &lasterror);
+ error = permission(dir,MAY_WRITE | MAY_EXEC);
if (error)
- goto exit;
- if(!lasterror) {
- error = -EEXIST;
- goto exit_inode;
- }
- if (!last.len) {
- error = -ENOENT;
- goto exit_inode;
- }
- if (IS_RDONLY(dir)) {
- error = -EROFS;
- goto exit_inode;
- }
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
- goto exit_inode;
- if (!dir->i_op || !dir->i_op->mkdir) {
- error = -ENOSYS; /* instead of EPERM, what does Posix say? */
- goto exit_inode;
- }
- atomic_inc(&dir->i_count);
+ goto exit_lock;
+
+ error = -EPERM;
+ if (!dir->i_op || !dir->i_op->mkdir)
+ goto exit_lock;
+
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
- down(&dir->i_sem);
- d_del(d_lookup(dir, &last, NULL), D_REMOVE);
- mode &= 01777 & ~current->fs->umask;
- error = dir->i_op->mkdir(dir, last.name, last.len, mode);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_print(dir->i_dentry, NULL, &last, " d %ld %d ",
- CURRENT_TIME, mode);
-#endif
+ mode &= 0777 & ~current->fs->umask;
+ error = dir->i_op->mkdir(dir, dentry, mode);
+
+exit_lock:
up(&dir->i_sem);
-exit_inode:
- if(!lasterror)
- iput(inode);
- iput(dir);
+ dput(dentry);
exit:
return error;
}
@@ -936,8 +726,9 @@ asmlinkage int sys_mkdir(const char * pathname, int mode)
char * tmp;
lock_kernel();
- error = getname(pathname,&tmp);
- if (!error) {
+ tmp = getname(pathname);
+ error = PTR_ERR(tmp);
+ if (!IS_ERR(tmp)) {
error = do_mkdir(tmp,mode);
putname(tmp);
}
@@ -945,124 +736,54 @@ asmlinkage int sys_mkdir(const char * pathname, int mode)
return error;
}
-#if 0 /* We need a "deletefs", someone please write it. -DaveM */
-/* Perhaps this could be moved out into a new file. */
-static void basket_name(struct inode * dir, struct dentry * entry)
-{
- char prefix[32];
- struct qstr prename = { prefix, 14 };
- struct qstr entname = { entry->d_name, entry->d_len };
- struct inode * inode;
- struct dentry * old = entry; /* dummy */
- int i;
- if(!entry || !(inode = d_inode(&entry)))
- return;
-#if 0
- if(atomic_read(&inode->i_count) > 2) {
- extern void printpath(struct dentry *entry);
-
- printk("Caution: in use ");
- if(inode->i_dentry)
- printpath(inode->i_dentry);
- printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n",
- inode->i_nlink, atomic_read(&inode->i_count),
- inode->i_ddir_count, inode->i_dent_count);
- }
-#endif
- vfs_lock();
- for(i = 1; old; i++) {
- sprintf(prefix, ".deleted-%04d.", i);
- old = d_lookup(dir, &prename, &entname);
- }
- d_move(entry, dir, &prename, &entname);
- vfs_unlock();
- iput(inode);
-}
-#endif
-
static inline int do_rmdir(const char * name)
{
- char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- struct qstr last;
- struct dentry * lastent = NULL;
int error;
- struct inode * dir;
- struct inode * inode;
-
- /* [T.Schoebel-Theuer] I'm not sure which flags to use here.
- * Try the following on different platforms:
- * [0] rm -rf test test2
- * [1] ln -s test2 test
- * [2] mkdir test || mkdir test2
- * [3] rmdir test && mkdir test2
- * [4] rmdir test/
- * Now the rusults:
- * cmd | HP-UX | SunOS | Solaris | Old Linux | New Linux |
- * ----------------------------------------------------------------
- * [2] | (OK) | EEXIST | EEXIST | EEXIST | (OK)
- * [3] | ENOTDIR | ENOTDIR | ENOTDIR | ENOTDIR | ENOTDIR
- * [4] | (OK) | EINVAL | ENOTDIR | ENOTDIR | (OK)
- * So I implemented the HP-UX semantics. If this is not right
- * for Posix compliancy, change the flags accordingly. If Posix
- * let the question open, I'd suggest to stay at the new semantics.
- * I'd even make case [3] work by adding 2 to the flags parameter
- * if Posix tolerates that.
- */
- error = __namei(NAM_FOLLOW_TRAILSLASH, name, NULL, buf,
- &dir, &inode, &last, &lastent, NULL);
- if (error)
+ struct inode *dir;
+ struct dentry *dentry;
+
+ dentry = lookup_dentry(name, NULL, 0);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto exit;
- if (IS_RDONLY(dir)) {
- error = -EROFS;
- goto exit_dir;
- }
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
- goto exit_dir;
+
+ dir = lock_parent(dentry);
+ error = -ENOENT;
+ if (!dentry->d_inode)
+ goto exit_lock;
+
+ error = -EROFS;
+ if (IS_RDONLY(dir))
+ goto exit_lock;
+
+ error = permission(dir,MAY_WRITE | MAY_EXEC);
+ if (error)
+ goto exit_lock;
+
/*
* A subdirectory cannot be removed from an append-only directory.
*/
- if (IS_APPEND(dir)) {
- error = -EPERM;
- goto exit_dir;
- }
- if (!dir->i_op || !dir->i_op->rmdir) {
- error = -ENOSYS; /* was EPERM */
- goto exit_dir;
- }
+ error = -EPERM;
+ if (IS_APPEND(dir))
+ goto exit_lock;
+
/* Disallow removals of mountpoints. */
- if(inode->i_mount) {
- error = -EBUSY;
- goto exit_dir;
- }
+ error = -EBUSY;
+ if (dentry->d_covers != dentry)
+ goto exit_lock;
+
+ error = -EPERM;
+ if (!dir->i_op || !dir->i_op->rmdir)
+ goto exit_lock;
+
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
- down(&dir->i_sem);
-#if 0
- if(lastent && d_isbasket(lastent)) {
- d_del(lastent, D_REMOVE);
- error = 0;
- goto exit_lock;
- }
-#endif
- atomic_inc(&dir->i_count);
- error = dir->i_op->rmdir(dir, last.name, last.len);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_print(lastent, NULL, NULL, " r %ld ", CURRENT_TIME);
-#endif
-#if 0
- if(!error && lastent)
- basket_name(dir, lastent);
+ error = dir->i_op->rmdir(dir, dentry);
+
exit_lock:
-#else
- if(!error && lastent)
- d_del(lastent, D_REMOVE);
-#endif
up(&dir->i_sem);
-exit_dir:
- iput(inode);
- iput(dir);
+ dput(dentry);
exit:
return error;
}
@@ -1073,8 +794,9 @@ asmlinkage int sys_rmdir(const char * pathname)
char * tmp;
lock_kernel();
- error = getname(pathname,&tmp);
- if (!error) {
+ tmp = getname(pathname);
+ error = PTR_ERR(tmp);
+ if (!IS_ERR(tmp)) {
error = do_rmdir(tmp);
putname(tmp);
}
@@ -1084,90 +806,44 @@ asmlinkage int sys_rmdir(const char * pathname)
static inline int do_unlink(const char * name)
{
- char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- struct qstr last;
- struct dentry * lastent = NULL;
int error;
- struct inode * dir;
- struct inode * inode;
-
- /* HP-UX shows a strange behaviour:
- * touch y; ln -s y x; rm x/
- * this succeeds and removes the file y, not the symlink x!
- * Solaris and old Linux remove the symlink instead, and
- * old SunOS complains ENOTDIR.
- * I chose the SunOS behaviour (by not using NAM_FOLLOW_TRAILSLASH),
- * but I'm not shure whether I should.
- * The current code generally prohibits using trailing slashes with
- * non-directories if the name already exists, but not if
- * it is to be newly created.
- * Perhaps this should be further strengthened (by introducing
- * an additional flag bit indicating whether trailing slashes are
- * allowed) to get it as consistant as possible, but I don't know
- * what Posix says.
- */
- error = __namei(NAM_NO_TRAILSLASH, name, NULL, buf,
- &dir, &inode, &last, &lastent, NULL);
- if (error)
+ struct inode *dir;
+ struct dentry *dentry;
+
+ dentry = lookup_dentry(name, NULL, 0);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto exit;
- if (IS_RDONLY(dir)) {
- error = -EROFS;
- goto exit_dir;
- }
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
- goto exit_dir;
+
+ dir = lock_parent(dentry);
+
+ error = -EROFS;
+ if (IS_RDONLY(dir))
+ goto exit_lock;
+
+ error = permission(dir,MAY_WRITE | MAY_EXEC);
+ if (error)
+ goto exit_lock;
+
/*
* A file cannot be removed from an append-only directory.
*/
- if (IS_APPEND(dir)) {
- error = -EPERM;
- goto exit_dir;
- }
- if (!dir->i_op || !dir->i_op->unlink) {
- error = -ENOSYS; /* was EPERM */
- goto exit_dir;
- }
+ error = -EPERM;
+ if (IS_APPEND(dir))
+ goto exit_lock;
+
+ error = -EPERM;
+ if (!dir->i_op || !dir->i_op->unlink)
+ goto exit_lock;
+
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
- down(&dir->i_sem);
-#if 0
- if(atomic_read(&inode->i_count) > 1) {
- extern void printpath(struct dentry *entry);
-
- printk("Fire ");
- if(lastent)
- printpath(lastent);
- printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n",
- inode->i_nlink, atomic_read(&inode->i_count),
- inode->i_ddir_count, inode->i_dent_count);
- }
-#endif
-#if 0
- if(lastent && d_isbasket(lastent)) {
- d_del(lastent, D_REMOVE);
- error = 0;
- goto exit_lock;
- }
-#endif
- atomic_inc(&dir->i_count);
- error = dir->i_op->unlink(dir, last.name, last.len);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_print(lastent, NULL, NULL, " u %ld ", CURRENT_TIME);
-#endif
-#if 0
- if(!error && lastent)
- basket_name(dir, lastent);
+ error = dir->i_op->unlink(dir, dentry);
+
exit_lock:
-#else
- if(!error && lastent)
- d_del(lastent, D_REMOVE);
-#endif
up(&dir->i_sem);
-exit_dir:
- iput(inode);
- iput(dir);
+ dput(dentry);
exit:
return error;
}
@@ -1178,8 +854,9 @@ asmlinkage int sys_unlink(const char * pathname)
char * tmp;
lock_kernel();
- error = getname(pathname,&tmp);
- if (!error) {
+ tmp = getname(pathname);
+ error = PTR_ERR(tmp);
+ if (!IS_ERR(tmp)) {
error = do_unlink(tmp);
putname(tmp);
}
@@ -1189,62 +866,41 @@ asmlinkage int sys_unlink(const char * pathname)
static inline int do_symlink(const char * oldname, const char * newname)
{
- char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- struct qstr last;
- int error, lasterror;
- struct inode * dir;
- struct inode * inode;
-
- /* The following works on HP-UX and Solaris, by producing
- * a symlink chain:
- * rm -rf ? ; mkdir z ; ln -s z y ; ln -s y x/
- * Under old SunOS, the following occurs:
- * ln: x/: No such file or directory
- * Under old Linux, very strange things occur:
- * ln: cannot create symbolic link `x//y' to `y': No such file or directory
- * This is very probably a bug, but may be caused by the ln program
- * when checking for a directory target.
- *
- * I'm not shure whether to add NAM_NO_TRAILSLASH to inhibit trailing
- * slashes in the target generally.
- */
- error = __namei(NAM_TRANSCREATE, newname, NULL, buf,
- &dir, &inode, &last, NULL, &lasterror);
- if (error)
+ int error;
+ struct inode *dir;
+ struct dentry *dentry;
+
+ dentry = lookup_dentry(newname, NULL, 0);
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto exit;
- if(!lasterror) {
- iput(inode);
- error = -EEXIST;
- goto exit_dir;
- }
- if (!last.len) {
- error = -ENOENT;
- goto exit_dir;
- }
- if (IS_RDONLY(dir)) {
- error = -EROFS;
- goto exit_dir;
- }
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
- goto exit_dir;
- if (!dir->i_op || !dir->i_op->symlink) {
- error = -ENOSYS; /* was EPERM */
- goto exit_dir;
- }
- atomic_inc(&dir->i_count);
+
+ error = -EEXIST;
+ if (dentry->d_inode)
+ goto exit;
+
+ dir = lock_parent(dentry);
+
+ error = -EROFS;
+ if (IS_RDONLY(dir))
+ goto exit_lock;
+
+ error = permission(dir,MAY_WRITE | MAY_EXEC);
+ if (error)
+ goto exit_lock;
+
+ error = -EPERM;
+ if (!dir->i_op || !dir->i_op->symlink)
+ goto exit_lock;
+
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
- down(&dir->i_sem);
- d_del(d_lookup(dir, &last, NULL), D_REMOVE);
- error = dir->i_op->symlink(dir, last.name, last.len, oldname);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_print(dir->i_dentry, NULL, &last,
- " s %ld %s\0", CURRENT_TIME, oldname);
-#endif
+ error = dir->i_op->symlink(dir, dentry, oldname);
+
+exit_lock:
up(&dir->i_sem);
-exit_dir:
- iput(dir);
+ dput(dentry);
exit:
return error;
}
@@ -1252,13 +908,16 @@ exit:
asmlinkage int sys_symlink(const char * oldname, const char * newname)
{
int error;
- char * from, * to;
+ char * from;
lock_kernel();
- error = getname(oldname,&from);
- if (!error) {
- error = getname(newname,&to);
- if (!error) {
+ from = getname(oldname);
+ error = PTR_ERR(from);
+ if (!IS_ERR(from)) {
+ char * to;
+ to = getname(newname);
+ error = PTR_ERR(to);
+ if (!IS_ERR(to)) {
error = do_symlink(from,to);
putname(to);
}
@@ -1270,73 +929,63 @@ asmlinkage int sys_symlink(const char * oldname, const char * newname)
static inline int do_link(const char * oldname, const char * newname)
{
- char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- struct qstr oldlast;
- struct qstr newlast;
- struct dentry * oldent = NULL;
- struct inode * oldinode;
- struct inode * newinode;
- struct inode * newdir;
- int error, lasterror;
-
- error = __namei(NAM_FOLLOW_LINK|NAM_NO_TRAILSLASH,
- oldname, NULL, oldbuf,
- NULL, &oldinode, &oldlast, &oldent, NULL);
- if (error)
+ struct dentry *old_dentry, *new_dentry;
+ struct inode *dir, *inode;
+ int error;
+
+ old_dentry = lookup_dentry(oldname, NULL, 1);
+ error = PTR_ERR(old_dentry);
+ if (IS_ERR(old_dentry))
goto exit;
- error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf,
- &newdir, &newinode, &newlast, NULL, &lasterror);
+ new_dentry = lookup_dentry(newname, NULL, 1);
+ error = PTR_ERR(new_dentry);
+ if (IS_ERR(new_dentry))
+ goto exit_old;
+
+ dir = lock_parent(new_dentry);
+
+ error = -ENOENT;
+ inode = old_dentry->d_inode;
+ if (!inode)
+ goto exit_lock;
+
+ error = -EEXIST;
+ if (new_dentry->d_inode)
+ goto exit_lock;
+
+ error = -EROFS;
+ if (IS_RDONLY(dir))
+ goto exit_lock;
+
+ error = -EXDEV;
+ if (dir->i_dev != inode->i_dev)
+ goto exit_lock;
+
+ error = permission(dir, MAY_WRITE | MAY_EXEC);
if (error)
- goto old_exit;
- if(!lasterror) {
- iput(newinode);
- error = -EEXIST;
- goto new_exit;
- }
- if (!newlast.len) {
- error = -EPERM;
- goto new_exit;
- }
- if (IS_RDONLY(newdir)) {
- error = -EROFS;
- goto new_exit;
- }
- if (newdir->i_dev != oldinode->i_dev) {
- error = -EXDEV;
- goto new_exit;
- }
- if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0)
- goto new_exit;
+ goto exit_lock;
+
/*
* A link to an append-only or immutable file cannot be created.
*/
- if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
- error = -EPERM;
- goto new_exit;
- }
- if (!newdir->i_op || !newdir->i_op->link) {
- error = -ENOSYS; /* was EPERM */
- goto new_exit;
- }
- atomic_inc(&oldinode->i_count);
- atomic_inc(&newdir->i_count);
- if (newdir->i_sb && newdir->i_sb->dq_op)
- newdir->i_sb->dq_op->initialize(newdir, -1);
- down(&newdir->i_sem);
- d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE);
- error = newdir->i_op->link(oldinode, newdir, newlast.name, newlast.len);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_print(oldent, newdir->i_dentry, &newlast,
- " l %ld ", CURRENT_TIME);
-#endif
- up(&newdir->i_sem);
-new_exit:
- iput(newdir);
-old_exit:
- iput(oldinode);
+ error = -EPERM;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ goto exit_lock;
+
+ error = -EPERM;
+ if (!dir->i_op || !dir->i_op->link)
+ goto exit_lock;
+
+ if (dir->i_sb && dir->i_sb->dq_op)
+ dir->i_sb->dq_op->initialize(dir, -1);
+ error = dir->i_op->link(inode, dir, new_dentry);
+
+exit_lock:
+ up(&dir->i_sem);
+ dput(new_dentry);
+exit_old:
+ dput(old_dentry);
exit:
return error;
}
@@ -1344,13 +993,16 @@ exit:
asmlinkage int sys_link(const char * oldname, const char * newname)
{
int error;
- char * from, * to;
+ char * from;
lock_kernel();
- error = getname(oldname,&from);
- if (!error) {
- error = getname(newname,&to);
- if (!error) {
+ from = getname(oldname);
+ error = PTR_ERR(from);
+ if (!IS_ERR(from)) {
+ char * to;
+ to = getname(newname);
+ error = PTR_ERR(to);
+ if (!IS_ERR(to)) {
error = do_link(from,to);
putname(to);
}
@@ -1360,105 +1012,111 @@ asmlinkage int sys_link(const char * oldname, const char * newname)
return error;
}
-static inline int do_rename(const char * oldname, const char * newname)
+/*
+ * Whee.. Deadlock country. Happily there is only one VFS
+ * operation that does this..
+ */
+static inline void double_down(struct semaphore *s1, struct semaphore *s2)
{
- char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- struct qstr oldlast;
- char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
- struct qstr newlast;
- struct dentry * oldent = NULL;
- struct inode * olddir, * newdir;
- struct inode * oldinode, * newinode;
- int error, newlasterror;
-
- error = __namei(NAM_FOLLOW_TRAILSLASH, oldname, NULL, oldbuf,
- &olddir, &oldinode, &oldlast, &oldent, NULL);
- if (error)
- goto exit;
- if ((error = permission(olddir,MAY_WRITE | MAY_EXEC)) != 0)
- goto old_exit;
- if (!oldlast.len || (oldlast.name[0] == '.' &&
- (oldlast.len == 1 || (oldlast.name[1] == '.' &&
- oldlast.len == 2)))) {
- error = -EPERM;
- goto old_exit;
+ if ((unsigned long) s1 < (unsigned long) s2) {
+ down(s1);
+ down(s2);
+ } else if (s1 == s2) {
+ down(s1);
+ atomic_dec(&s1->count);
+ } else {
+ down(s2);
+ down(s1);
}
- /* Disallow moves of mountpoints. */
- if(oldinode->i_mount) {
- error = -EBUSY;
- goto old_exit;
+}
+
+static inline int is_reserved(struct dentry *dentry)
+{
+ if (dentry->d_name.name[0] == '.') {
+ switch (dentry->d_name.len) {
+ case 2:
+ if (dentry->d_name.name[1] != '.')
+ break;
+ /* fallthrough */
+ case 1:
+ return 1;
+ }
}
+ return 0;
+}
+
+static inline int do_rename(const char * oldname, const char * newname)
+{
+ int error;
+ struct inode * old_dir, * new_dir;
+ struct dentry * old_dentry, *new_dentry;
+
+ old_dentry = lookup_dentry(oldname, NULL, 0);
+
+ error = PTR_ERR(old_dentry);
+ if (IS_ERR(old_dentry))
+ goto exit;
+
+ new_dentry = lookup_dentry(newname, NULL, 0);
+
+ error = PTR_ERR(new_dentry);
+ if (IS_ERR(new_dentry))
+ goto exit_old;
+
+ new_dir = get_parent(new_dentry);
+ old_dir = get_parent(old_dentry);
+
+ double_down(&new_dir->i_sem, &old_dir->i_sem);
- error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf,
- &newdir, &newinode, &newlast, NULL, &newlasterror);
+ error = -ENOENT;
+ if (!old_dentry->d_inode)
+ goto exit_lock;
+
+ error = permission(old_dir,MAY_WRITE | MAY_EXEC);
if (error)
- goto old_exit;
- if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0)
- goto new_exit;
- if (!newlast.len || (newlast.name[0] == '.' &&
- (newlast.len == 1 || (newlast.name[1] == '.' &&
- newlast.len == 2)))) {
- error = -EPERM;
- goto new_exit;
- }
- if (newdir->i_dev != olddir->i_dev) {
- error = -EXDEV;
- goto new_exit;
- }
- if (IS_RDONLY(newdir) || IS_RDONLY(olddir)) {
- error = -EROFS;
- goto new_exit;
- }
+ goto exit_lock;
+ error = permission(new_dir,MAY_WRITE | MAY_EXEC);
+ if (error)
+ goto exit_lock;
+
+ error = -EPERM;
+ if (is_reserved(new_dentry) || is_reserved(old_dentry))
+ goto exit_lock;
+
+ /* Disallow moves of mountpoints. */
+ error = -EBUSY;
+ if (old_dentry->d_covers != old_dentry)
+ goto exit_lock;
+
+ error = -EXDEV;
+ if (new_dir->i_dev != old_dir->i_dev)
+ goto exit_lock;
+
+ error = -EROFS;
+ if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir))
+ goto exit_lock;
+
/*
* A file cannot be removed from an append-only directory.
*/
- if (IS_APPEND(olddir)) {
- error = -EPERM;
- goto new_exit;
- }
- if (!olddir->i_op || !olddir->i_op->rename) {
- error = -ENOSYS; /* was EPERM */
- goto new_exit;
- }
-#ifdef CONFIG_TRANS_NAMES
- /* if oldname has been translated, but newname not (and
- * has not already a suffix), take over the suffix from oldname.
- */
- if(oldlast.name == oldbuf && newlast.name != newbuf &&
- newlast.name[newlast.len-1] != '#') {
- int i = oldlast.len - 2;
- while (i > 0 && oldlast.name[i] != '#')
- i--;
- memcpy(newbuf, newlast.name, newlast.len);
- memcpy(newbuf+newlast.len, oldlast.name+i, oldlast.len - i);
- newlast.len += oldlast.len - i;
- newlast.name = newbuf;
- }
-#endif
- atomic_inc(&olddir->i_count);
- atomic_inc(&newdir->i_count);
- if (newdir->i_sb && newdir->i_sb->dq_op)
- newdir->i_sb->dq_op->initialize(newdir, -1);
- down(&newdir->i_sem);
- error = olddir->i_op->rename(olddir, oldlast.name, oldlast.len,
- newdir, newlast.name, newlast.len);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_print(oldent, newdir->i_dentry, &newlast,
- " m %ld ", CURRENT_TIME);
-#endif
- if(!error) {
- d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE);
- d_move(d_lookup(olddir, &oldlast, NULL), newdir, &newlast, NULL);
- }
- up(&newdir->i_sem);
-new_exit:
- if(!newlasterror)
- iput(newinode);
- iput(newdir);
-old_exit:
- iput(oldinode);
- iput(olddir);
+ error = -EPERM;
+ if (IS_APPEND(old_dir))
+ goto exit_lock;
+
+ error = -EPERM;
+ if (!old_dir->i_op || !old_dir->i_op->rename)
+ goto exit_lock;
+
+ if (new_dir->i_sb && new_dir->i_sb->dq_op)
+ new_dir->i_sb->dq_op->initialize(new_dir, -1);
+ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+
+exit_lock:
+ up(&new_dir->i_sem);
+ up(&old_dir->i_sem);
+ dput(new_dentry);
+exit_old:
+ dput(old_dentry);
exit:
return error;
}
@@ -1466,13 +1124,16 @@ exit:
asmlinkage int sys_rename(const char * oldname, const char * newname)
{
int error;
- char * from, * to;
+ char * from;
lock_kernel();
- error = getname(oldname,&from);
- if (!error) {
- error = getname(newname,&to);
- if (!error) {
+ from = getname(oldname);
+ error = PTR_ERR(from);
+ if (!IS_ERR(from)) {
+ char * to;
+ to = getname(newname);
+ error = PTR_ERR(to);
+ if (!IS_ERR(to)) {
error = do_rename(from,to);
putname(to);
}
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 72ca3e6dd..83309f3a6 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -408,7 +408,7 @@ int ncp_current_malloced;
static struct file_system_type ncp_fs_type = {
"ncpfs",
- FS_NO_DCACHE,
+ 0 /* FS_NO_DCACHE doesn't work correctly */,
ncp_read_super,
NULL
};
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 8e814d153..937f40cec 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -132,8 +132,8 @@ int ncp_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma)
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
- vma->vm_inode = inode;
- atomic_inc(&inode->i_count);
+
+ vma->vm_dentry = dget(file->f_dentry);
vma->vm_ops = &ncp_file_mmap;
return 0;
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 71835c255..b10331c6a 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -42,16 +42,15 @@ struct nfs_dirent {
static int nfs_dir_open(struct inode * inode, struct file * file);
static long nfs_dir_read(struct inode *, struct file *, char *, unsigned long);
static int nfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int nfs_lookup(struct inode *, const char *, int, struct inode **);
-static int nfs_create(struct inode *, const char *, int, int, struct inode **);
-static int nfs_mkdir(struct inode *, const char *, int, int);
-static int nfs_rmdir(struct inode *, const char *, int);
-static int nfs_unlink(struct inode *, const char *, int);
-static int nfs_symlink(struct inode *, const char *, int, const char *);
-static int nfs_link(struct inode *, struct inode *, const char *, int);
-static int nfs_mknod(struct inode *, const char *, int, int, int);
-static int nfs_rename(struct inode *, const char *, int,
- struct inode *, const char *, int);
+static int 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 *);
+static int nfs_unlink(struct inode *, struct dentry *);
+static int nfs_symlink(struct inode *, struct dentry *, const char *);
+static int nfs_link(struct inode *, struct inode *, struct dentry *);
+static int nfs_mknod(struct inode *, struct dentry *, int, int);
+static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
static struct file_operations nfs_dir_operations = {
NULL, /* lseek - default */
@@ -78,6 +77,7 @@ struct inode_operations nfs_dir_inode_operations = {
nfs_mknod, /* mknod */
nfs_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -328,488 +328,267 @@ nfs_free_dircache(void)
}
-/*
- * Lookup caching is a big win for performance but this is just
- * a trial to see how well it works on a small scale.
- * For example, bash does a lookup on ".." 13 times for each path
- * element when running pwd. Yes, hard to believe but true.
- * Try pwd in a filesystem mounted with noac.
- *
- * It trades a little cpu time and memory for a lot of network bandwidth.
- * Since the cache is not hashed yet, it is a good idea not to make it too
- * large because every lookup looks through the entire cache even
- * though most of them will fail.
- *
- * FIXME: The lookup cache should also cache failed lookups. This can
- * be a considerable win on diskless clients.
- */
-
-static struct nfs_lookup_cache_entry {
- kdev_t dev;
- ino_t inode;
- char filename[NFS_MAXNAMLEN + 1];
- struct nfs_fh fhandle;
- struct nfs_fattr fattr;
- unsigned long expiration_date;
-} nfs_lookup_cache[NFS_LOOKUP_CACHE_SIZE];
-
-static struct nfs_lookup_cache_entry *nfs_lookup_cache_index(struct inode *dir,
- const char *filename)
-{
- struct nfs_lookup_cache_entry *entry;
- int i;
-
- for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
- entry = nfs_lookup_cache + i;
- if (entry->dev == dir->i_dev
- && entry->inode == dir->i_ino
- && !strncmp(filename, entry->filename, NFS_MAXNAMLEN))
- return entry;
- }
- return NULL;
-}
-
-static int nfs_lookup_cache_lookup(struct inode *dir, const char *filename,
- struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
-{
- static int nfs_lookup_cache_in_use = 0;
-
- struct nfs_lookup_cache_entry *entry;
-
- dfprintk(LOOKUPCACHE, "NFS: lookup_cache_lookup(%x/%ld, %s)\n",
- dir->i_dev, dir->i_ino, filename);
- if (!nfs_lookup_cache_in_use) {
- memset(nfs_lookup_cache, 0, sizeof(nfs_lookup_cache));
- nfs_lookup_cache_in_use = 1;
- }
- if ((entry = nfs_lookup_cache_index(dir, filename))) {
- if (jiffies > entry->expiration_date) {
- entry->dev = 0;
- return 0;
- }
- *fhandle = entry->fhandle;
- *fattr = entry->fattr;
- return 1;
- }
- return 0;
-}
-
-static void nfs_lookup_cache_add(struct inode *dir, const char *filename,
- struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
-{
- static int nfs_lookup_cache_pos = 0;
- struct nfs_lookup_cache_entry *entry;
-
- dfprintk(LOOKUPCACHE, "NFS: lookup_cache_add(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, filename);
-
- /* compensate for bug in SGI NFS server */
- if (fattr->size == -1 || fattr->uid == -1 || fattr->gid == -1
- || fattr->atime.seconds == -1 || fattr->mtime.seconds == -1)
- return;
- if (!(entry = nfs_lookup_cache_index(dir, filename))) {
- entry = nfs_lookup_cache + nfs_lookup_cache_pos++;
- if (nfs_lookup_cache_pos == NFS_LOOKUP_CACHE_SIZE)
- nfs_lookup_cache_pos = 0;
- }
-
- entry->dev = dir->i_dev;
- entry->inode = dir->i_ino;
- strcpy(entry->filename, filename);
- entry->fhandle = *fhandle;
- entry->fattr = *fattr;
- entry->expiration_date = jiffies + (S_ISDIR(fattr->mode)
- ? NFS_SERVER(dir)->acdirmin : NFS_SERVER(dir)->acregmin);
-}
-
-static void nfs_lookup_cache_remove(struct inode *dir, struct inode *inode,
- const char *filename)
-{
- struct nfs_lookup_cache_entry *entry;
- kdev_t dev;
- ino_t fileid;
- int i;
-
- if (inode) {
- dev = inode->i_dev;
- fileid = inode->i_ino;
- }
- else if ((entry = nfs_lookup_cache_index(dir, filename))) {
- dev = entry->dev;
- fileid = entry->fattr.fileid;
- }
- else
- return;
-
- dfprintk(LOOKUPCACHE, "NFS: lookup_cache_remove(%x/%ld)\n",
- dev, (long)fileid);
-
- for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
- entry = nfs_lookup_cache + i;
- if (entry->dev == dev && entry->fattr.fileid == fileid)
- entry->dev = 0;
- }
-}
-
-static void nfs_lookup_cache_refresh(struct inode *file,
- struct nfs_fattr *fattr)
-{
- struct nfs_lookup_cache_entry *entry;
- kdev_t dev = file->i_dev;
- int fileid = file->i_ino;
- int i;
-
- for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
- entry = nfs_lookup_cache + i;
- if (entry->dev == dev && entry->fattr.fileid == fileid)
- entry->fattr = *fattr;
- }
-}
-
-static int nfs_lookup(struct inode *dir, const char *__name, int len,
- struct inode **result)
+static int nfs_lookup(struct inode *dir, struct dentry * dentry)
{
+ struct inode *inode;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
- char name[len > NFS_MAXNAMLEN? 1 : len+1];
+ int len = dentry->d_name.len;
int error;
dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n",
- dir->i_dev, dir->i_ino, len, __name);
+ dir->i_dev, dir->i_ino, len, dentry->d_name.name);
- *result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_lookup: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
- memcpy(name,__name,len);
- name[len] = '\0';
- if (len == 0 || (len == 1 && name[0] == '.')) { /* cheat for "" and "." */
- *result = dir;
- return 0;
- }
- if ((NFS_SERVER(dir)->flags & NFS_MOUNT_NOAC)
- || !nfs_lookup_cache_lookup(dir, name, &fhandle, &fattr)) {
- if ((error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
- name, &fhandle, &fattr))) {
- iput(dir);
- return error;
- }
- nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
- }
- if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) {
- iput(dir);
- return -EACCES;
- }
- iput(dir);
+
+ error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &fhandle, &fattr);
+
+ inode = NULL;
+ if (!error) {
+ error = -ENOENT;
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
+ return -EACCES;
+ } else if (error != -ENOENT)
+ return error;
+
+ d_add(dentry, inode);
return 0;
}
-static int nfs_create(struct inode *dir, const char *name, int len, int mode,
- struct inode **result)
+static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
+ struct inode *inode;
int error;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
- *result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_create: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
+
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
- if ((error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
- name, &sattr, &fhandle, &fattr))) {
- iput(dir);
+ error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+
+ if (error)
return error;
- }
- if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) {
- iput(dir);
+
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
return -EACCES;
- }
- nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
- nfs_invalidate_dircache(dir);
- iput(dir);
+
+ d_instantiate(dentry, inode);
return 0;
}
-static int nfs_mknod(struct inode *dir, const char *name, int len,
- int mode, int rdev)
+static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
+ struct inode *inode;
int error;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_mknod: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
+
sattr.mode = mode;
- sattr.uid = sattr.gid = (unsigned) -1;
+ sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
if (S_ISCHR(mode) || S_ISBLK(mode))
sattr.size = rdev; /* get out your barf bag */
- else
- sattr.size = (unsigned) -1;
+
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
- name, &sattr, &fhandle, &fattr);
- if (!error)
- nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+
+ if (error)
+ return error;
+
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
+ return -EACCES;
+
+ d_instantiate(dentry, inode);
+ return 0;
}
-static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode)
+static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
+ struct inode * inode;
int error;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_mkdir: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
+
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+
error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
- name, &sattr, &fhandle, &fattr);
- if (!error)
- nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+
+ if (error)
+ return error;
+
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
+ return -EACCES;
+
+ d_instantiate(dentry, inode);
+ return 0;
}
-static int nfs_rmdir(struct inode *dir, const char *name, int len)
+static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
int error;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_rmdir: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
- return -ENAMETOOLONG;
- }
- error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), name);
- if (!error)
- nfs_lookup_cache_remove(dir, NULL, name);
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
-}
-
-static int nfs_sillyrename(struct inode *dir, const char *name, int len)
-{
- struct inode *inode;
- char silly[16];
- int slen, ret;
-
- atomic_inc(&dir->i_count);
- if (nfs_lookup(dir, name, len, &inode) < 0)
- return -EIO; /* arbitrary */
-
- if (atomic_read(&inode->i_count) == 1) {
- iput(inode);
- return -EIO;
- }
- if (NFS_RENAMED_DIR(inode)) {
- iput(NFS_RENAMED_DIR(inode));
- NFS_RENAMED_DIR(inode) = NULL;
- iput(inode);
- return -EIO;
- }
- slen = sprintf(silly, ".nfs%ld", inode->i_ino);
- if (len == slen && !strncmp(name, silly, len)) {
- iput(inode);
- return -EIO; /* DWIM */
- }
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
+ return -ENAMETOOLONG;
- dfprintk(VFS, "NFS: sillyrename(%x/%ld, %s)\n",
- dir->i_dev, dir->i_ino, name);
+ error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
+ if (error)
+ return error;
- ret = nfs_proc_rename(NFS_SERVER(dir), NFS_FH(dir), name,
- NFS_FH(dir), silly);
- if (ret >= 0) {
- nfs_lookup_cache_remove(dir, NULL, name);
- nfs_lookup_cache_remove(dir, NULL, silly);
- NFS_RENAMED_DIR(inode) = dir;
- atomic_inc(&dir->i_count);
- }
- nfs_invalidate_dircache(dir);
- iput(inode);
- return ret;
+ d_delete(dentry);
+ return 0;
}
/*
- * When releasing the inode, finally remove any unlinked but open files.
- * Note that we have to clear the set of pending signals temporarily;
- * otherwise the RPC call will fail.
+ * We should do silly-rename here, but I'm too lazy to fix
+ * up the directory entry implications of it..
*/
-void nfs_sillyrename_cleanup(struct inode *inode)
-{
- unsigned long oldsig;
- struct inode *dir = NFS_RENAMED_DIR(inode);
- char silly[14];
- int error, slen;
-
- dfprintk(VFS, "NFS: sillyrename cleanup(%x/%ld)\n",
- inode->i_dev, inode->i_ino);
-
- oldsig = current->signal;
- current->signal = 0;
-
- slen = sprintf(silly, ".nfs%ld", inode->i_ino);
- error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), silly);
- if (error < 0)
- printk("NFS: silly_rename cleanup failed (err %d)\n", -error);
-
- nfs_lookup_cache_remove(dir, NULL, silly);
- nfs_invalidate_dircache(dir);
- NFS_RENAMED_DIR(inode) = NULL;
- iput(dir);
-
- current->signal |= oldsig;
-}
-
-static int nfs_unlink(struct inode *dir, const char *name, int len)
+static int nfs_unlink(struct inode *dir, struct dentry *dentry)
{
int error;
dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_unlink: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
- if ((error = nfs_sillyrename(dir, name, len)) < 0) {
- error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), name);
- if (!error)
- nfs_lookup_cache_remove(dir, NULL, name);
- }
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
+
+ error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
+ if (error)
+ return error;
+
+ d_delete(dentry);
+ return 0;
}
-static int nfs_symlink(struct inode *dir, const char *name, int len,
- const char *symname)
+static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
struct nfs_sattr sattr;
+ struct nfs_fattr fattr;
+ struct nfs_fh fhandle;
+ struct inode * inode;
int error;
dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
- dir->i_dev, dir->i_ino, name, symname);
+ dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_symlink: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
- if (strlen(symname) > NFS_MAXPATHLEN) {
- iput(dir);
+
+ if (strlen(symname) > NFS_MAXPATHLEN)
return -ENAMETOOLONG;
- }
+
sattr.mode = S_IFLNK | S_IRWXUGO; /* SunOS 4.1.2 crashes without this! */
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+
error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
- name, symname, &sattr);
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
+ dentry->d_name.name, symname, &sattr);
+
+ if (error)
+ return error;
+
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
+ return -EACCES;
+
+ d_instantiate(dentry, inode);
+ return 0;
}
-static int nfs_link(struct inode *oldinode, struct inode *dir,
- const char *name, int len)
+static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry)
{
int error;
dfprintk(VFS, "NFS: link(%x/%ld -> %x/%ld, %s)\n",
- oldinode->i_dev, oldinode->i_ino,
- dir->i_dev, dir->i_ino, name);
+ inode->i_dev, inode->i_ino,
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
- if (!oldinode) {
- printk("nfs_link: old inode is NULL\n");
- iput(oldinode);
- iput(dir);
- return -ENOENT;
- }
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_link: dir is NULL or not a directory\n");
- iput(oldinode);
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(oldinode);
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
- error = nfs_proc_link(NFS_SERVER(oldinode), NFS_FH(oldinode),
- NFS_FH(dir), name);
- if (!error) {
- nfs_lookup_cache_remove(dir, oldinode, NULL);
- NFS_READTIME(oldinode) = 0; /* force getattr */
- }
- nfs_invalidate_dircache(dir);
- iput(oldinode);
- iput(dir);
- return error;
+
+ error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode),
+ NFS_FH(dir), dentry->d_name.name);
+
+ if (error)
+ return error;
+
+ inode->i_count++;
+ d_instantiate(dentry, inode);
+ return 0;
}
/*
@@ -821,45 +600,39 @@ static int nfs_link(struct inode *oldinode, struct inode *dir,
* rename the old file using the silly_rename stuff. This way, the original
* file in old_dir will go away when the last process iput()s the inode.
*/
-static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len)
+static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
int error;
dfprintk(VFS, "NFS: rename(%x/%ld, %s -> %x/%ld, %s)\n",
- old_dir->i_dev, old_dir->i_ino, old_name,
- new_dir->i_dev, new_dir->i_ino, new_name);
+ old_dir->i_dev, old_dir->i_ino, old_dentry->d_name.name,
+ new_dir->i_dev, new_dir->i_ino, new_dentry->d_name.name);
if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
printk("nfs_rename: old inode is NULL or not a directory\n");
- iput(old_dir);
- iput(new_dir);
return -ENOENT;
}
+
if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
printk("nfs_rename: new inode is NULL or not a directory\n");
- iput(old_dir);
- iput(new_dir);
return -ENOENT;
}
- if (old_len > NFS_MAXNAMLEN || new_len > NFS_MAXNAMLEN) {
- iput(old_dir);
- iput(new_dir);
+
+ if (old_dentry->d_name.len > NFS_MAXNAMLEN || new_dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
error = nfs_proc_rename(NFS_SERVER(old_dir),
- NFS_FH(old_dir), old_name,
- NFS_FH(new_dir), new_name);
- if (!error) {
- nfs_lookup_cache_remove(old_dir, NULL, old_name);
- nfs_lookup_cache_remove(new_dir, NULL, new_name);
- }
- nfs_invalidate_dircache(old_dir);
- nfs_invalidate_dircache(new_dir);
- iput(old_dir);
- iput(new_dir);
- return error;
+ NFS_FH(old_dir), old_dentry->d_name.name,
+ NFS_FH(new_dir), new_dentry->d_name.name);
+
+ if (error)
+ return error;
+
+ /* Update the dcache */
+ d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
+ d_delete(new_dentry);
+ return 0;
}
/*
@@ -873,8 +646,7 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
int was_empty;
dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
- inode->i_dev, inode->i_ino,
- atomic_read(&inode->i_count));
+ inode->i_dev, inode->i_ino, inode->i_count);
if (!inode || !fattr) {
printk("nfs_refresh_inode: inode or fattr is NULL\n");
@@ -925,6 +697,4 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
init_fifo(inode);
} else
inode->i_op = NULL;
- nfs_lookup_cache_refresh(inode, fattr);
}
-
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 56540bbdc..eb4735a6d 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -69,6 +69,7 @@ struct inode_operations nfs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
nfs_readpage, /* readpage */
nfs_writepage, /* writepage */
NULL, /* bmap */
@@ -142,7 +143,7 @@ nfs_file_write(struct inode *inode, struct file *file,
int result;
dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n",
- inode->i_dev, inode->i_ino, atomic_read(&inode->i_count),
+ inode->i_dev, inode->i_ino, inode->i_count,
count, (unsigned long) file->f_pos);
if (!inode) {
@@ -179,11 +180,11 @@ nfs_lock(struct inode *inode, struct file *filp, int cmd, struct file_lock *fl)
int status;
dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%ld:%ld)\n",
- filp->f_inode->i_dev, filp->f_inode->i_ino,
+ filp->f_dentry->d_inode->i_dev, filp->f_dentry->d_inode->i_ino,
fl->fl_type, fl->fl_flags,
fl->fl_start, fl->fl_end);
- if (!(inode = filp->f_inode))
+ if (!(inode = filp->f_dentry->d_inode))
return -EINVAL;
/* No mandatory locks over NFS */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5ab9600e9..cf52a0d56 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -36,15 +36,17 @@
static int nfs_notify_change(struct inode *, struct iattr *);
static void nfs_put_inode(struct inode *);
+static void nfs_delete_inode(struct inode *);
static void nfs_put_super(struct super_block *);
static void nfs_read_inode(struct inode *);
-static void nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
+static int nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
static struct super_operations nfs_sops = {
nfs_read_inode, /* read inode */
- nfs_notify_change, /* notify change */
NULL, /* write inode */
nfs_put_inode, /* put inode */
+ nfs_delete_inode, /* delete inode */
+ nfs_notify_change, /* notify change */
nfs_put_super, /* put superblock */
NULL, /* write superblock */
nfs_statfs, /* stat filesystem */
@@ -73,11 +75,16 @@ static void
nfs_put_inode(struct inode * inode)
{
dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+}
- if (NFS_RENAMED_DIR(inode))
- nfs_sillyrename_cleanup(inode);
- if (inode->i_pipe)
- clear_inode(inode);
+/*
+ * This should do any silly-rename cleanups once we
+ * get silly-renaming working again..
+ */
+static void
+nfs_delete_inode(struct inode * inode)
+{
+ dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
}
void
@@ -230,7 +237,8 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
/* Unlock super block and try to get root fh attributes */
unlock_super(sb);
- if ((sb->s_mounted = nfs_fhget(sb, &data->root, NULL)) != NULL) {
+ sb->s_root = d_alloc_root(nfs_fhget(sb, &data->root, NULL), NULL);
+ if (sb->s_root != NULL) {
/* We're airborne */
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_up();
@@ -250,7 +258,7 @@ failure:
return NULL;
}
-static void
+static int
nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
int error;
@@ -271,7 +279,7 @@ nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
tmp.f_files = 0;
tmp.f_ffree = 0;
tmp.f_namelen = NAME_MAX;
- copy_to_user(buf, &tmp, bufsiz);
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
/*
@@ -317,7 +325,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
}
dprintk("NFS: fhget(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino,
- atomic_read(&inode->i_count));
+ inode->i_count);
return inode;
}
@@ -364,7 +372,6 @@ nfs_notify_change(struct inode *inode, struct iattr *attr)
nfs_truncate_dirty_pages(inode, sattr.size);
nfs_refresh_inode(inode, &fattr);
}
- inode->i_dirt = 0;
return error;
}
@@ -435,7 +442,7 @@ done:
*/
static struct file_system_type nfs_fs_type = {
"nfs",
- FS_NO_DCACHE,
+ 0 /* FS_NO_DCACHE - this doesn't work right now*/,
nfs_read_super,
NULL
};
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index add3309f3..51cca7c48 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -1,5 +1,5 @@
/*
- * $Id: nfsroot.c,v 1.37 1997/06/04 08:28:10 davem Exp $
+ * $Id: nfsroot.c,v 1.3 1997/06/17 13:26:56 ralf Exp $
*
* Copyright (C) 1995, 1996 Gero Kuhlmann <gero@gkminix.han.de>
*
@@ -78,7 +78,6 @@
#include <asm/param.h>
#include <linux/utsname.h>
-#include <linux/nametrans.h>
#include <linux/in.h>
#include <linux/if.h>
#include <linux/inet.h>
@@ -833,9 +832,6 @@ __initfunc(static void root_do_bootp_ext(u8 *ext))
root_bootp_string(nfs_path, ext+1, *ext, NFS_MAXPATHLEN);
break;
}
-#ifdef CONFIG_TRANS_NAMES
- translations_dirty = 1;
-#endif
}
@@ -1258,9 +1254,6 @@ __initfunc(static void root_nfs_addrs(char *addrs))
system_utsname.domainname[0] = '\0';
user_dev_name[0] = '\0';
bootp_flag = rarp_flag = 1;
-#ifdef CONFIG_TRANS_NAMES
- translations_dirty = 1;
-#endif
/* The following is just a shortcut for automatic IP configuration */
if (!strcmp(addrs, "bootp")) {
@@ -1306,9 +1299,6 @@ __initfunc(static void root_nfs_addrs(char *addrs))
}
strncpy(system_utsname.nodename, ip, __NEW_UTS_LEN);
system_utsname.nodename[__NEW_UTS_LEN] = '\0';
-#ifdef CONFIG_TRANS_NAMES
- translations_dirty = 1;
-#endif
break;
case 5:
strncpy(user_dev_name, ip, IFNAMSIZ);
@@ -1342,9 +1332,6 @@ __initfunc(static int root_nfs_setup(void))
if (!system_utsname.nodename[0]) {
strncpy(system_utsname.nodename, in_ntoa(myaddr), __NEW_UTS_LEN);
system_utsname.nodename[__NEW_UTS_LEN] = '\0';
-#ifdef CONFIG_TRANS_NAMES
- translations_dirty = 1;
-#endif
}
/* Set the correct netmask */
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 2c3b59036..4ce61f731 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -150,7 +150,6 @@ nfs_readpage_result(struct rpc_task *task)
fail++;
dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
}
- iput(req->ra_inode);
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
@@ -188,7 +187,6 @@ nfs_readpage_async(struct inode *inode, struct page *page)
nfs_readpage_result, req);
if (result >= 0) {
- atomic_inc(&inode->i_count);
atomic_inc(&page->count);
return 0;
}
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index a22f96239..3d545f7d8 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -19,6 +19,7 @@
#include <asm/uaccess.h>
static int nfs_readlink(struct inode *, char *, int);
+static struct dentry *nfs_follow_link(struct inode *, struct dentry *);
/*
* symlinks can't do much...
@@ -35,6 +36,7 @@ struct inode_operations nfs_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
nfs_readlink, /* readlink */
+ nfs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -55,7 +57,6 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
buflen = NFS_MAXPATHLEN;
error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
&res, &len, buflen);
- iput(inode);
if (! error) {
copy_to_user(buffer, res, len);
put_user('\0', buffer + len);
@@ -64,3 +65,36 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
kfree(mem);
return error;
}
+
+static struct dentry * nfs_follow_link(struct inode * inode, struct dentry *base)
+{
+ int error;
+ unsigned int len;
+ char *res;
+ void *mem;
+ char *path;
+
+ dfprintk(VFS, "nfs: follow_link(%x/%ld)\n", inode->i_dev, inode->i_ino);
+
+ error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
+ &res, &len, NFS_MAXPATHLEN);
+
+ if (error) {
+ dput(base);
+ kfree(mem);
+ return ERR_PTR(error);
+ }
+ path = kmalloc(len + 1, GFP_KERNEL);
+ if (!path) {
+ dput(base);
+ kfree(mem);
+ return ERR_PTR(-ENOMEM);
+ }
+ memcpy(path, res, len);
+ path[len] = 0;
+ kfree(mem);
+
+ base = lookup_dentry(path, base, 1);
+ kfree(path);
+ return base;
+}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index f27d083e4..9241c679e 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -338,7 +338,7 @@ create_write_request(struct inode *inode, struct page *page,
wreq->wb_page = page;
wreq->wb_offset = offset;
wreq->wb_bytes = bytes;
- atomic_inc(&inode->i_count);
+
atomic_inc(&page->count);
append_write_request(&NFS_WRITEBACK(inode), wreq);
@@ -695,7 +695,6 @@ nfs_check_error(struct inode *inode)
status = req->wb_task.tk_status;
remove_write_request(&nfs_failed_requests, req);
- iput(req->wb_inode);
kfree(req);
return status;
}
@@ -788,7 +787,6 @@ nfs_wback_result(struct rpc_task *task)
dprintk("NFS: %4d saving write failure code\n",
task->tk_pid);
append_write_request(&nfs_failed_requests, req);
- atomic_inc(&inode->i_count);
}
clear_bit(PG_uptodate, &page->flags);
} else if (!WB_CANCELLED(req)) {
@@ -818,6 +816,5 @@ nfs_wback_result(struct rpc_task *task)
kfree(req);
free_page(page_address(page));
- iput(inode);
nr_write_requests--;
}
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index a3b29313a..c83150b5f 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -331,7 +331,7 @@ exp_rootfh(struct svc_client *clp, dev_t dev, ino_t ino, struct knfs_fh *f)
if (!(exp = exp_get(clp, dev, ino)))
return -EPERM;
- atomic_inc(&exp->ex_inode->i_count);
+ exp->ex_inode->i_count++;
fh_compose(&fh, exp, exp->ex_inode);
memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
fh_put(&fh);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index a68fca997..b6fdb460d 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -120,13 +120,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
dotdot = (len == 2 && name[0] == '.' && name[1] == '.');
if (dotdot) {
if (dirp == current->fs->root) {
- atomic_inc(&dirp->i_count);
+ dirp->i_count++;
*resfh = *fhp;
return 0;
}
if (dirp->i_dev == exp->ex_dev && dirp->i_ino == exp->ex_ino) {
- atomic_inc(&dirp->i_count);
+ dirp->i_count++;
*resfh = *fhp;
return 0;
}
@@ -144,12 +144,12 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
if (perm != 0)
return perm;
if (!len) {
- atomic_inc(&dirp->i_count);
+ dirp->i_count++;
*resfh = *fhp;
return 0;
}
- atomic_inc(&dirp->i_count); /* lookup eats the dirp inode */
+ dirp->i_count++; /* lookup eats the dirp inode */
err = dirp->i_op->lookup(dirp, name, len, &inode);
if (err)
@@ -162,7 +162,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
if (!dotdot && (sb = inode->i_sb) && (inode == sb->s_mounted)) {
iput(inode);
inode = sb->s_covered;
- atomic_inc(&inode->i_count);
+ inode->i_count++;
}
fh_compose(resfh, exp, inode);
@@ -291,7 +291,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
}
}
- atomic_inc(&inode->i_count);
+ inode->i_count++;
return 0;
}
@@ -304,7 +304,7 @@ nfsd_close(struct file *filp)
struct inode *inode;
inode = filp->f_inode;
- if (!atomic_read(&inode->i_count))
+ if (!inode->i_count)
printk(KERN_WARNING "nfsd: inode count == 0!\n");
if (filp->f_op && filp->f_op->release)
filp->f_op->release(inode, filp);
@@ -533,7 +533,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
fh_lock(fhp); /* lock directory */
dirp = fhp->fh_inode;
- atomic_inc(&dirp->i_count); /* dirop eats the inode */
+ dirp->i_count++; /* dirop eats the inode */
switch (type) {
case S_IFREG:
@@ -568,7 +568,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
* If the VFS call doesn't return the inode, look it up now.
*/
if (inode == NULL) {
- atomic_inc(&dirp->i_count);
+ dirp->i_count++;
err = dirp->i_op->lookup(dirp, fname, flen, &inode);
if (err < 0)
return -nfserrno(err); /* Huh?! */
@@ -643,7 +643,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
if (!inode->i_op || !inode->i_op->readlink)
return nfserr_io;
- atomic_inc(&inode->i_count);
+ inode->i_count++;
oldfs = get_fs(); set_fs(KERNEL_DS);
err = inode->i_op->readlink(inode, buf, *lenp);
set_fs(oldfs);
@@ -680,7 +680,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
return nfserr_perm;
fh_lock(fhp); /* lock inode */
- atomic_inc(&dirp->i_count);
+ dirp->i_count++;
err = dirp->i_op->symlink(dirp, fname, flen, path);
fh_unlock(fhp); /* unlock inode */
@@ -693,7 +693,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
/*
* Okay, now look up the inode of the new symlink.
*/
- atomic_inc(&dirp->i_count); /* lookup eats the dirp inode */
+ dirp->i_count++; /* lookup eats the dirp inode */
err = dirp->i_op->lookup(dirp, fname, flen, &inode);
if (err)
return nfserrno(-err);
@@ -730,7 +730,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
return nfserr_perm;
fh_lock(ffhp); /* lock directory inode */
- atomic_inc(&dirp->i_count);
+ dirp->i_count++;
err = dirp->i_op->link(dest, dirp, fname, len);
fh_unlock(ffhp); /* unlock inode */
@@ -770,8 +770,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
return nfserr_perm;
fh_lock(tfhp); /* lock destination directory */
- atomic_inc(&tdir->i_count);
- atomic_inc(&fdir->i_count);
+ tdir->i_count++;
+ fdir->i_count++;
err = fdir->i_op->rename(fdir, fname, flen, tdir, tname, tlen);
fh_unlock(tfhp); /* unlock inode */
@@ -805,12 +805,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (type == S_IFDIR) {
if (!dirp->i_op || !dirp->i_op->rmdir)
return nfserr_notdir;
- atomic_inc(&dirp->i_count);
+ dirp->i_count++;
err = dirp->i_op->rmdir(dirp, fname, flen);
} else { /* other than S_IFDIR */
if (!dirp->i_op || !dirp->i_op->unlink)
return nfserr_perm;
- atomic_inc(&dirp->i_count);
+ dirp->i_count++;
err = dirp->i_op->unlink(dirp, fname, flen);
}
diff --git a/fs/open.c b/fs/open.c
index 70b8a8a58..3408fb2a6 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -4,7 +4,6 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/config.h>
#include <linux/vfs.h>
#include <linux/types.h>
#include <linux/utime.h>
@@ -21,32 +20,27 @@
#include <linux/file.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
-#include <linux/omirr.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
asmlinkage int sys_statfs(const char * path, struct statfs * buf)
{
- struct inode * inode;
+ struct dentry * dentry;
int error;
lock_kernel();
- error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
- if (error)
- goto out;
- error = namei(NAM_FOLLOW_LINK, path, &inode);
- if (error)
- goto out;
- error = -ENOSYS;
- if (!inode->i_sb->s_op->statfs) {
- iput(inode);
- goto out;
+ dentry = namei(path);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+
+ error = -ENOSYS;
+ if (inode->i_sb->s_op->statfs)
+ error = inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
+
+ dput(dentry);
}
- inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
- iput(inode);
- error = 0;
-out:
unlock_kernel();
return error;
}
@@ -54,6 +48,7 @@ out:
asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
{
struct inode * inode;
+ struct dentry * dentry;
struct file * file;
int error;
@@ -63,7 +58,9 @@ asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
goto out;
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
error = -EBADF;
- else if (!(inode = file->f_inode))
+ else if (!(dentry = file->f_dentry))
+ error = -ENOENT;
+ else if (!(inode = dentry->d_inode))
error = -ENOENT;
else if (!inode->i_sb)
error = -ENODEV;
@@ -90,7 +87,6 @@ int do_truncate(struct inode *inode, unsigned long length)
vmtruncate(inode, length);
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
- inode->i_status |= ST_MODIFIED;
}
up(&inode->i_sem);
return error;
@@ -98,33 +94,37 @@ int do_truncate(struct inode *inode, unsigned long length)
asmlinkage int sys_truncate(const char * path, unsigned long length)
{
+ struct dentry * dentry;
struct inode * inode;
int error;
lock_kernel();
- error = namei(NAM_FOLLOW_LINK, path, &inode);
- if (error)
+ dentry = namei(path);
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
+ inode = dentry->d_inode;
error = -EACCES;
if (S_ISDIR(inode->i_mode))
- goto iput_and_out;
+ goto dput_and_out;
error = permission(inode,MAY_WRITE);
if (error)
- goto iput_and_out;
+ goto dput_and_out;
error = -EROFS;
if (IS_RDONLY(inode))
- goto iput_and_out;
+ goto dput_and_out;
error = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
- goto iput_and_out;
+ goto dput_and_out;
error = get_write_access(inode);
if (error)
- goto iput_and_out;
+ goto dput_and_out;
error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
length < inode->i_size ? length : inode->i_size,
@@ -135,8 +135,8 @@ asmlinkage int sys_truncate(const char * path, unsigned long length)
error = do_truncate(inode, length);
}
put_write_access(inode);
-iput_and_out:
- iput(inode);
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
@@ -145,13 +145,16 @@ out:
asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
{
struct inode * inode;
+ struct dentry *dentry;
struct file * file;
int error;
lock_kernel();
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
error = -EBADF;
- else if (!(inode = file->f_inode))
+ else if (!(dentry = file->f_dentry))
+ error = -ENOENT;
+ else if (!(inode = dentry->d_inode))
error = -ENOENT;
else if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
error = -EACCES;
@@ -184,17 +187,21 @@ asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
asmlinkage int sys_utime(char * filename, struct utimbuf * times)
{
int error;
+ struct dentry * dentry;
struct inode * inode;
struct iattr newattrs;
lock_kernel();
- /* Hmm, should I always follow symlinks or not ? */
- error = namei(NAM_FOLLOW_LINK, filename, &inode);
- if (error)
+ dentry = namei(filename);
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
+ inode = dentry->d_inode;
+
error = -EROFS;
if (IS_RDONLY(inode))
- goto iput_and_out;
+ goto dput_and_out;
/* Don't worry, the checks are done in inode_change_ok() */
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
@@ -203,22 +210,17 @@ asmlinkage int sys_utime(char * filename, struct utimbuf * times)
if (!error)
error = get_user(newattrs.ia_mtime, &times->modtime);
if (error)
- goto iput_and_out;
+ goto dput_and_out;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
} else {
if (current->fsuid != inode->i_uid &&
(error = permission(inode,MAY_WRITE)) != 0)
- goto iput_and_out;
+ goto dput_and_out;
}
error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME,
- newattrs.ia_atime, newattrs.ia_mtime);
-#endif
-iput_and_out:
- iput(inode);
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
@@ -233,38 +235,39 @@ out:
asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
{
int error;
+ struct dentry * dentry;
struct inode * inode;
struct iattr newattrs;
lock_kernel();
- error = namei(NAM_FOLLOW_LINK, filename, &inode);
- if (error)
+ dentry = namei(filename);
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
+ inode = dentry->d_inode;
+
error = -EROFS;
if (IS_RDONLY(inode))
- goto iput_and_out;
+ goto dput_and_out;
+
/* Don't worry, the checks are done in inode_change_ok() */
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
if (utimes) {
struct timeval times[2];
error = -EFAULT;
if (copy_from_user(&times, utimes, sizeof(times)))
- goto iput_and_out;
+ goto dput_and_out;
newattrs.ia_atime = times[0].tv_sec;
newattrs.ia_mtime = times[1].tv_sec;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
} else {
if ((error = permission(inode,MAY_WRITE)) != 0)
- goto iput_and_out;
+ goto dput_and_out;
}
error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME,
- newattrs.ia_atime, newattrs.ia_mtime);
-#endif
-iput_and_out:
- iput(inode);
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
@@ -276,7 +279,7 @@ out:
*/
asmlinkage int sys_access(const char * filename, int mode)
{
- struct inode * inode;
+ struct dentry * dentry;
int old_fsuid, old_fsgid;
int res = -EINVAL;
@@ -287,11 +290,14 @@ asmlinkage int sys_access(const char * filename, int mode)
old_fsgid = current->fsgid;
current->fsuid = current->uid;
current->fsgid = current->gid;
- res = namei(NAM_FOLLOW_LINK, filename, &inode);
- if (!res) {
- res = permission(inode, mode);
- iput(inode);
+
+ dentry = namei(filename);
+ res = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ res = permission(dentry->d_inode, mode);
+ dput(dentry);
}
+
current->fsuid = old_fsuid;
current->fsgid = old_fsgid;
out:
@@ -301,24 +307,34 @@ out:
asmlinkage int sys_chdir(const char * filename)
{
- struct inode * inode;
- struct inode * tmpi;
int error;
+ struct inode *inode;
+ struct dentry *dentry, *tmp;
lock_kernel();
- error = namei(NAM_FOLLOW_LINK, filename, &inode);
- if (error)
+
+ dentry = namei(filename);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
+
+ inode = dentry->d_inode;
+
error = -ENOTDIR;
if (!S_ISDIR(inode->i_mode))
- goto iput_and_out;
- if ((error = permission(inode,MAY_EXEC)) != 0)
- goto iput_and_out;
-
- /* exchange inodes */
- tmpi = current->fs->pwd; current->fs->pwd = inode; inode = tmpi;
-iput_and_out:
- iput(inode);
+ goto dput_and_out;
+
+ error = permission(inode,MAY_EXEC);
+ if (error)
+ goto dput_and_out;
+
+ /* exchange dentries */
+ tmp = current->fs->pwd;
+ current->fs->pwd = dentry;
+ dentry = tmp;
+
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
@@ -326,24 +342,38 @@ out:
asmlinkage int sys_fchdir(unsigned int fd)
{
- struct inode * inode;
- struct file * file;
- int error = -EBADF;
+ struct file *file;
+ struct dentry *dentry;
+ struct inode *inode;
+ int error;
lock_kernel();
+
+ error = -EBADF;
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
goto out;
+
error = -ENOENT;
- if (!(inode = file->f_inode))
+ if (!(dentry = file->f_dentry))
goto out;
+ if (!(inode = dentry->d_inode))
+ goto out;
+
error = -ENOTDIR;
if (!S_ISDIR(inode->i_mode))
goto out;
- if ((error = permission(inode,MAY_EXEC)) != 0)
+
+ error = permission(inode,MAY_EXEC);
+ if (error)
goto out;
- iput(current->fs->pwd);
- current->fs->pwd = inode;
- atomic_inc(&inode->i_count);
+
+ {
+ struct dentry *tmp;
+
+ tmp = current->fs->pwd;
+ current->fs->pwd = dget(dentry);
+ dput(tmp);
+ }
out:
unlock_kernel();
return error;
@@ -351,24 +381,39 @@ out:
asmlinkage int sys_chroot(const char * filename)
{
- struct inode * inode;
- struct inode * tmpi;
int error;
+ struct inode *inode;
+ struct dentry *dentry, *tmp;
lock_kernel();
- error = namei(NAM_FOLLOW_LINK, filename, &inode);
- if (error)
+
+ dentry = namei(filename);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
+
+ inode = dentry->d_inode;
+
error = -ENOTDIR;
if (!S_ISDIR(inode->i_mode))
- goto iput_and_out;
+ goto dput_and_out;
+
+ error = permission(inode,MAY_EXEC);
+ if (error)
+ goto dput_and_out;
+
error = -EPERM;
if (!fsuser())
- goto iput_and_out;
- tmpi = current->fs->root; current->fs->root = inode; inode = tmpi;
+ goto dput_and_out;
+
+ /* exchange dentries */
+ tmp = current->fs->root;
+ current->fs->root = dentry;
+ dentry = tmp;
error = 0;
-iput_and_out:
- iput(inode);
+
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
@@ -377,6 +422,7 @@ out:
asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
{
struct inode * inode;
+ struct dentry * dentry;
struct file * file;
struct iattr newattrs;
int err = -EBADF;
@@ -385,7 +431,9 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
goto out;
err = -ENOENT;
- if (!(inode = file->f_inode))
+ if (!(dentry = file->f_dentry))
+ goto out;
+ if (!(inode = dentry->d_inode))
goto out;
err = -EROFS;
if (IS_RDONLY(inode))
@@ -397,12 +445,7 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- inode->i_dirt = 1;
err = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!err)
- omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
-#endif
out:
unlock_kernel();
return err;
@@ -410,54 +453,51 @@ out:
asmlinkage int sys_chmod(const char * filename, mode_t mode)
{
+ struct dentry * dentry;
struct inode * inode;
int error;
struct iattr newattrs;
lock_kernel();
- /* I'm not sure whether to use NAM_FOLLOW_TRAILSLASH instead,
- * because permissions on symlinks now can never be changed,
- * but on the other hand they are never needed.
- */
- error = namei(NAM_FOLLOW_LINK, filename, &inode);
- if (error)
+ dentry = namei(filename);
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
+ inode = dentry->d_inode;
+
error = -EROFS;
if (IS_RDONLY(inode))
- goto iput_and_out;
+ goto dput_and_out;
+
error = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
- goto iput_and_out;
+ goto dput_and_out;
+
if (mode == (mode_t) -1)
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- inode->i_dirt = 1;
error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
-#endif
-iput_and_out:
- iput(inode);
+
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
}
-asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
+static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
{
struct inode * inode;
- struct file * file;
struct iattr newattrs;
- int error = -EBADF;
+ int error;
- lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- goto out;
error = -ENOENT;
- if (!(inode = file->f_inode))
+ if (!(inode = dentry->d_inode)) {
+ printk("chown_common: NULL inode\n");
goto out;
+ }
error = -EROFS;
if (IS_RDONLY(inode))
goto out;
@@ -489,7 +529,6 @@ asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
newattrs.ia_mode &= ~S_ISGID;
newattrs.ia_valid |= ATTR_MODE;
}
- inode->i_dirt = 1;
if (inode->i_sb && inode->i_sb->dq_op) {
inode->i_sb->dq_op->initialize(inode, -1);
error = -EDQUOT;
@@ -500,80 +539,70 @@ asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
} else
error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_printall(inode, " O %d %d ", CURRENT_TIME,
- newattrs.ia_uid, newattrs.ia_gid);
-#endif
out:
- unlock_kernel();
return error;
}
+asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group)
+{
+ struct dentry * dentry;
+ int error;
+
+ lock_kernel();
+ dentry = lnamei(filename);
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out;
+
+ error = chown_common(dentry, user, group);
+
+ dput(dentry);
+out:
+ unlock_kernel();
+ return(error);
+}
+
asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
{
- struct inode * inode;
+ struct dentry * dentry;
int error;
- struct iattr newattrs;
lock_kernel();
- error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
- if (error)
+ dentry = namei(filename);
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
- error = -EROFS;
- if (IS_RDONLY(inode))
- goto iput_and_out;
- error = -EPERM;
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
- goto iput_and_out;
- if (user == (uid_t) -1)
- user = inode->i_uid;
- if (group == (gid_t) -1)
- group = inode->i_gid;
- newattrs.ia_mode = inode->i_mode;
- newattrs.ia_uid = user;
- newattrs.ia_gid = group;
- newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
- /*
- * If the owner has been changed, remove the setuid bit
- */
- if (inode->i_mode & S_ISUID) {
- newattrs.ia_mode &= ~S_ISUID;
- newattrs.ia_valid |= ATTR_MODE;
- }
- /*
- * If the group has been changed, remove the setgid bit
- *
- * Don't remove the setgid bit if no group execute bit.
- * This is a file marked for mandatory locking.
- */
- if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
- newattrs.ia_mode &= ~S_ISGID;
- newattrs.ia_valid |= ATTR_MODE;
- }
- inode->i_dirt = 1;
- if (inode->i_sb->dq_op) {
- inode->i_sb->dq_op->initialize(inode, -1);
- error = -EDQUOT;
- if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
- goto iput_and_out;
- error = notify_change(inode, &newattrs);
- if (error)
- inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
- } else
- error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_printall(inode, " O %d %d ", CURRENT_TIME,
- newattrs.ia_uid, newattrs.ia_gid);
-#endif
-iput_and_out:
- iput(inode);
+
+ error = chown_common(dentry, user, group);
+
+ dput(dentry);
out:
unlock_kernel();
return(error);
}
+asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
+{
+ struct dentry * dentry;
+ struct file * file;
+ int error = -EBADF;
+
+ lock_kernel();
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ goto out;
+ error = -ENOENT;
+ if (!(dentry = file->f_dentry))
+ goto out;
+
+ error = chown_common(dentry, user, group);
+
+out:
+ unlock_kernel();
+ return error;
+}
+
/*
* Note that while the flag value (low two bits) for sys_open means:
* 00 - read-only
@@ -591,6 +620,7 @@ out:
static int do_open(const char * filename,int flags,int mode, int fd)
{
struct inode * inode;
+ struct dentry * dentry;
struct file * f;
int flag,error;
@@ -603,16 +633,18 @@ static int do_open(const char * filename,int flags,int mode, int fd)
flag++;
if (flag & O_TRUNC)
flag |= 2;
- error = open_namei(filename,flag,mode,&inode,NULL);
- if (error)
+ dentry = open_namei(filename,flag,mode);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto cleanup_file;
+ inode = dentry->d_inode;
if (f->f_mode & FMODE_WRITE) {
error = get_write_access(inode);
if (error)
- goto cleanup_inode;
+ goto cleanup_dentry;
}
- f->f_inode = inode;
+ f->f_dentry = dentry;
f->f_pos = 0;
f->f_reada = 0;
f->f_op = NULL;
@@ -631,8 +663,8 @@ static int do_open(const char * filename,int flags,int mode, int fd)
cleanup_all:
if (f->f_mode & FMODE_WRITE)
put_write_access(inode);
-cleanup_inode:
- iput(inode);
+cleanup_dentry:
+ dput(dentry);
cleanup_file:
put_filp(f);
return error;
@@ -666,14 +698,15 @@ asmlinkage int sys_open(const char * filename,int flags,int mode)
int fd, error;
lock_kernel();
- fd = get_unused_fd();
- if (fd < 0) {
- error = fd;
+ error = get_unused_fd();
+ if (error < 0)
goto out;
- }
- error = getname(filename, &tmp);
- if (!error) {
- error = do_open(tmp,flags,mode, fd);
+
+ fd = error;
+ tmp = getname(filename);
+ error = PTR_ERR(tmp);
+ if (!IS_ERR(tmp)) {
+ error = do_open(tmp,flags,mode,fd);
putname(tmp);
if (!error) {
error = fd;
@@ -704,31 +737,35 @@ asmlinkage int sys_creat(const char * pathname, int mode)
#endif
-int __fput(struct file *filp, struct inode *inode)
+int __fput(struct file *filp)
{
int error = 0;
+ struct dentry * dentry = filp->f_dentry;
+ struct inode * inode = dentry->d_inode;
if (filp->f_op && filp->f_op->release)
error = filp->f_op->release(inode,filp);
- filp->f_inode = NULL;
+ filp->f_dentry = NULL;
if (filp->f_mode & FMODE_WRITE)
put_write_access(inode);
- iput(inode);
+ dput(dentry);
return error;
}
int close_fp(struct file *filp)
{
+ struct dentry *dentry;
struct inode *inode;
if (filp->f_count == 0) {
printk("VFS: Close: file count is 0\n");
return 0;
}
- inode = filp->f_inode;
+ dentry = filp->f_dentry;
+ inode = dentry->d_inode;
if (inode)
locks_remove_locks(current, filp);
- return fput(filp, inode);
+ return fput(filp);
}
asmlinkage int sys_close(unsigned int fd)
diff --git a/fs/pipe.c b/fs/pipe.c
index 732d37af5..0188409e8 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -75,10 +75,7 @@ static long pipe_read(struct inode * inode, struct file * filp,
PIPE_LOCK(*inode)--;
wake_up_interruptible(&PIPE_WAIT(*inode));
if (read) {
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
+ UPDATE_ATIME(inode);
return read;
}
if (PIPE_WRITERS(*inode))
@@ -132,7 +129,7 @@ static long pipe_write(struct inode * inode, struct file * filp,
free = 1;
}
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return written;
}
@@ -168,7 +165,7 @@ static int pipe_ioctl(struct inode *pino, struct file * filp,
static unsigned int pipe_poll(struct file * filp, poll_table * wait)
{
unsigned int mask;
- struct inode * inode = filp->f_inode;
+ struct inode * inode = filp->f_dentry->d_inode;
poll_wait(&PIPE_WAIT(*inode), wait);
mask = POLLIN | POLLRDNORM;
@@ -189,7 +186,7 @@ static unsigned int pipe_poll(struct file * filp, poll_table * wait)
static unsigned int fifo_poll(struct file * filp, poll_table * wait)
{
unsigned int mask;
- struct inode * inode = filp->f_inode;
+ struct inode * inode = filp->f_dentry->d_inode;
poll_wait(&PIPE_WAIT(*inode), wait);
mask = POLLIN | POLLRDNORM;
@@ -221,7 +218,7 @@ static long connect_read(struct inode * inode, struct file * filp,
static unsigned int connect_poll(struct file * filp, poll_table * wait)
{
- struct inode * inode = filp->f_inode;
+ struct inode * inode = filp->f_dentry->d_inode;
poll_wait(&PIPE_WAIT(*inode), wait);
if (!PIPE_EMPTY(*inode)) {
@@ -233,18 +230,26 @@ static unsigned int connect_poll(struct file * filp, poll_table * wait)
return POLLOUT | POLLWRNORM;
}
-static int pipe_read_release(struct inode * inode, struct file * filp)
+static int pipe_release(struct inode * inode)
{
- PIPE_READERS(*inode)--;
+ if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) {
+ free_page((unsigned long) PIPE_BASE(*inode));
+ PIPE_BASE(*inode) = NULL;
+ }
wake_up_interruptible(&PIPE_WAIT(*inode));
return 0;
}
+static int pipe_read_release(struct inode * inode, struct file * filp)
+{
+ PIPE_READERS(*inode)--;
+ return pipe_release(inode);
+}
+
static int pipe_write_release(struct inode * inode, struct file * filp)
{
PIPE_WRITERS(*inode)--;
- wake_up_interruptible(&PIPE_WAIT(*inode));
- return 0;
+ return pipe_release(inode);
}
static int pipe_rdwr_release(struct inode * inode, struct file * filp)
@@ -253,8 +258,7 @@ static int pipe_rdwr_release(struct inode * inode, struct file * filp)
PIPE_READERS(*inode)--;
if (filp->f_mode & FMODE_WRITE)
PIPE_WRITERS(*inode)--;
- wake_up_interruptible(&PIPE_WAIT(*inode));
- return 0;
+ return pipe_release(inode);
}
static int pipe_read_open(struct inode * inode, struct file * filp)
@@ -373,6 +377,42 @@ struct file_operations rdwr_pipe_fops = {
NULL
};
+static struct inode * get_pipe_inode(void)
+{
+ extern struct inode_operations pipe_inode_operations;
+ struct inode *inode = get_empty_inode();
+
+ if (inode) {
+ unsigned long page = __get_free_page(GFP_USER);
+
+ if (!page) {
+ iput(inode);
+ inode = NULL;
+ } else {
+ PIPE_BASE(*inode) = (char *) page;
+ inode->i_op = &pipe_inode_operations;
+ PIPE_WAIT(*inode) = NULL;
+ PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
+ PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
+ PIPE_LOCK(*inode) = 0;
+ /*
+ * Mark the inode dirty from the very beginning,
+ * that way it will never be moved to the dirty
+ * list because "make_inode_dirty()" will think
+ * that it already _is_ on the dirty list.
+ */
+ inode->i_state = 1 << I_DIRTY;
+ inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blksize = PAGE_SIZE;
+ }
+ }
+ return inode;
+}
+
struct inode_operations pipe_inode_operations = {
&rdwr_pipe_fops,
NULL, /* create */
@@ -422,12 +462,14 @@ int do_pipe(int *fd)
goto close_f12_inode_i;
j = error;
- f1->f_inode = f2->f_inode = inode;
+ f1->f_dentry = f2->f_dentry = dget(d_alloc_root(inode, NULL));
+
/* read file */
f1->f_pos = f2->f_pos = 0;
f1->f_flags = O_RDONLY;
f1->f_op = &read_pipe_fops;
f1->f_mode = 1;
+
/* write file */
f2->f_flags = O_WRONLY;
f2->f_op = &write_pipe_fops;
@@ -441,7 +483,6 @@ int do_pipe(int *fd)
close_f12_inode_i:
put_unused_fd(i);
close_f12_inode:
- atomic_dec(&inode->i_count);
iput(inode);
close_f12:
put_filp(f2);
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 6f336245d..68e2a3485 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := proc.o
-O_OBJS := inode.o root.o base.o generic.o mem.o link.o arbitrary.o fd.o array.o \
+O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
kmsg.o scsi.o proc_tty.o
ifdef CONFIG_OMIRR
O_OBJS := $(O_OBJS) omirr.o
diff --git a/fs/proc/arbitrary.c b/fs/proc/arbitrary.c
deleted file mode 100644
index 1e18e594e..000000000
--- a/fs/proc/arbitrary.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * $Id: arbitrary.c,v 1.2 1997/06/05 01:27:47 davem Exp $
- *
- * linux/fs/proc/arbitrary.c - lookup() for arbitrary inodes.
- * Copyright (C) 1997, Thomas Schoebel-Theuer,
- * <schoebel@informatik.uni-stuttgart.de>.
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/kdev_t.h>
-#include <linux/fs.h>
-
-/* Format of dev/inode pairs that can be used as file names:
- * [<dev_number_in_hex]:<inode_number_in_decimal>
- * (the same format that is already in use in /proc/<pid>/exe,
- * /proc/<pid>/cwd and /proc/<pid>/root).
- */
-/* Note that readdir does not supply such names, so they must be used
- * either "blind" or must be queried another way, for example
- * as result of a virtual symlink (see linux/proc/link.c).
- */
-int proc_arbitrary_lookup(struct inode * dir, const char * name,
- int len, struct inode ** result)
-{
- int dev, ino;
- char * ptr = (char*)name;
- kdev_t kdev;
- int i;
- int error = -EINVAL;
-
- if(*ptr++ != '[')
- goto done;
- dev = simple_strtoul(ptr, &ptr, 16);
- if(*ptr++ != ']')
- goto done;
- if(*ptr++ != ':')
- goto done;
- ino = simple_strtoul(ptr, &ptr, 0);
- if((long)ptr - (long)name != len)
- goto done;
-
- error = -ENOENT;
- kdev = to_kdev_t(dev);
- if(!kdev)
- goto done;
- for(i = 0; i < NR_SUPER; i++)
- if(super_blocks[i].s_dev == kdev)
- break;
- if(i < NR_SUPER) {
- *result = iget(&super_blocks[i], ino);
- if(*result)
- error = 0;
- }
-done:
- iput(dir);
- return error;
-}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 518ef1b4c..773b96873 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -612,7 +612,7 @@ static inline char * task_mem(struct task_struct *p, char *buffer)
for (vma = mm->mmap; vma; vma = vma->vm_next) {
unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
- if (!vma->vm_inode) {
+ if (!vma->vm_dentry) {
data += len;
if (vma->vm_flags & VM_GROWSDOWN)
stack += len;
@@ -970,12 +970,11 @@ static long read_maps (int pid, struct file * file,
*cp++ = flags & VM_MAYSHARE ? 's' : 'p';
*cp++ = 0;
- if (map->vm_inode != NULL) {
- dev = map->vm_inode->i_dev;
- ino = map->vm_inode->i_ino;
- } else {
- dev = 0;
- ino = 0;
+ dev = 0;
+ ino = 0;
+ if (map->vm_dentry != NULL) {
+ dev = map->vm_dentry->d_inode->i_dev;
+ ino = map->vm_dentry->d_inode->i_ino;
}
len = sprintf(line,
@@ -1237,6 +1236,7 @@ struct inode_operations proc_array_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -1282,6 +1282,7 @@ struct inode_operations proc_arraylong_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/base.c b/fs/proc/base.c
index b983e73f6..7e9a65e08 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -42,6 +42,7 @@ static struct inode_operations proc_base_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 884631db8..1e1fb494f 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -14,7 +14,7 @@
#include <linux/stat.h>
static int proc_readfd(struct inode *, struct file *, void *, filldir_t);
-static int proc_lookupfd(struct inode *,const char *,int,struct inode **);
+static int proc_lookupfd(struct inode *, struct dentry *);
static struct file_operations proc_fd_operations = {
NULL, /* lseek - default */
@@ -44,6 +44,7 @@ struct inode_operations proc_fd_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -51,39 +52,36 @@ struct inode_operations proc_fd_inode_operations = {
NULL /* permission */
};
-static int proc_lookupfd(struct inode * dir, const char * name, int len,
- struct inode ** result)
+/*
+ * NOTE! Normally we'd indicate that a file does not
+ * exist by creating a negative dentry and returning
+ * a successful return code. However, for this case
+ * we do not want to create negative dentries, because
+ * the state of the world can change behind our backs.
+ *
+ * Thus just return -ENOENT instead.
+ */
+static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
{
unsigned int ino, pid, fd, c;
struct task_struct * p;
struct super_block * sb;
+ struct inode *inode;
+ const char *name;
+ int len;
- *result = NULL;
ino = dir->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
if (!dir)
return -ENOENT;
sb = dir->i_sb;
- if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode)) {
- iput(dir);
+ if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode))
return -ENOENT;
- }
- if (!len || (name[0] == '.' && (len == 1 ||
- (name[1] == '.' && len == 2)))) {
- if (len < 2) {
- *result = dir;
- return 0;
- }
- if (!(*result = proc_get_inode(sb, (pid << 16)+PROC_PID_INO, &proc_pid))) {
- iput(dir);
- return -ENOENT;
- }
- iput(dir);
- return 0;
- }
- iput(dir);
+
fd = 0;
+ len = dentry->d_name.len;
+ name = dentry->d_name.name;
while (len-- > 0) {
c = *name - '0';
name++;
@@ -111,13 +109,16 @@ static int proc_lookupfd(struct inode * dir, const char * name, int len,
if (fd >= NR_OPEN ||
!p->files ||
!p->files->fd[fd] ||
- !p->files->fd[fd]->f_inode)
+ !p->files->fd[fd]->f_dentry)
return -ENOENT;
ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
- if (!(*result = proc_get_inode(sb, ino, NULL)))
+ inode = proc_get_inode(sb, ino, NULL);
+ if (!inode)
return -ENOENT;
+
+ d_add(dentry, inode);
return 0;
}
@@ -155,7 +156,7 @@ static int proc_readfd(struct inode * inode, struct file * filp,
for (fd -= 2 ; fd < NR_OPEN; fd++, filp->f_pos++) {
if (!p->files)
break;
- if (!p->files->fd[fd] || !p->files->fd[fd]->f_inode)
+ if (!p->files->fd[fd] || !p->files->fd[fd]->f_dentry)
continue;
j = NUMBUF;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 1424dd1ef..358060020 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -23,6 +23,15 @@ static long proc_file_write(struct inode * inode, struct file * file,
static long long proc_file_lseek(struct inode * inode, struct file * file,
long long offset, int orig);
+int proc_match(int len, const char *name,struct proc_dir_entry * de)
+{
+ if (!de || !de->low_ino)
+ return 0;
+ if (de->namelen != len)
+ return 0;
+ return !memcmp(name, de->name, len);
+}
+
static struct file_operations proc_file_operations = {
proc_file_lseek, /* lseek */
proc_file_read, /* read */
@@ -51,6 +60,7 @@ struct inode_operations proc_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -73,6 +83,7 @@ struct inode_operations proc_net_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 943137bf4..4bc4a4f17 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -25,8 +25,14 @@ static void proc_put_inode(struct inode *inode)
&& proc_openprom_use)
(*proc_openprom_use)(inode, 0);
#endif
- if (inode->i_nlink)
- return;
+}
+
+/*
+ * Does this ever happen?
+ */
+static void proc_delete_inode(struct inode *inode)
+{
+ printk("proc_delete_inode()?\n");
inode->i_size = 0;
}
@@ -39,9 +45,10 @@ static void proc_put_super(struct super_block *sb)
static struct super_operations proc_sops = {
proc_read_inode,
- NULL,
proc_write_inode,
proc_put_inode,
+ proc_delete_inode,
+ NULL,
proc_put_super,
NULL,
proc_statfs,
@@ -131,16 +138,17 @@ struct super_block *proc_read_super(struct super_block *s,void *data,
s->s_magic = PROC_SUPER_MAGIC;
s->s_op = &proc_sops;
unlock_super(s);
- if (!(s->s_mounted = proc_get_inode(s, PROC_ROOT_INO, &proc_root))) {
+ s->s_root = d_alloc_root(proc_get_inode(s, PROC_ROOT_INO, &proc_root), NULL);
+ if (!s->s_root) {
s->s_dev = 0;
printk("get root inode failed\n");
return NULL;
}
- parse_options(data, &s->s_mounted->i_uid, &s->s_mounted->i_gid);
+ parse_options(data, &s->s_root->d_inode->i_uid, &s->s_root->d_inode->i_gid);
return s;
}
-void proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
@@ -152,7 +160,7 @@ void proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
tmp.f_files = 0;
tmp.f_ffree = 0;
tmp.f_namelen = NAME_MAX;
- copy_to_user(buf, &tmp, bufsiz);
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
void proc_read_inode(struct inode * inode)
@@ -200,5 +208,4 @@ void proc_read_inode(struct inode * inode)
void proc_write_inode(struct inode * inode)
{
- inode->i_dirt=0;
}
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index 6ef386ffa..1cc6a9c83 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -70,6 +70,7 @@ struct inode_operations proc_kmsg_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/link.c b/fs/proc/link.c
index 695ed9bba..c25fd702b 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -14,9 +14,9 @@
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
-#include <linux/dalloc.h>
static int proc_readlink(struct inode *, char *, int);
+static struct dentry * proc_follow_link(struct inode *, struct dentry *);
/*
* PLAN9_SEMANTICS won't work any more: it used an ugly hack that broke
@@ -52,6 +52,7 @@ struct inode_operations proc_link_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
proc_readlink, /* readlink */
+ proc_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -59,59 +60,52 @@ struct inode_operations proc_link_inode_operations = {
NULL /* permission */
};
-/* [Feb-1997 T. Schoebel-Theuer] This is no longer called from the
- * VFS, but only from proc_readlink(). All the functionality
- * should the moved there (without using temporary inodes any more)
- * and then it could be eliminated.
- */
-static int proc_follow_link(struct inode * dir, struct inode * inode,
- int flag, int mode, struct inode ** res_inode)
+static struct dentry * proc_follow_link(struct inode *inode, struct dentry *base)
{
- unsigned int pid, ino;
- struct task_struct * p;
- struct inode * new_inode;
+ struct task_struct *p;
+ struct dentry * result;
+ int ino, pid;
int error;
- *res_inode = NULL;
- if (dir)
- iput(dir);
- if (!inode)
- return -ENOENT;
- if ((error = permission(inode, MAY_EXEC)) != 0){
- iput(inode);
- return error;
- }
+ /* We don't need a base pointer in the /proc filesystem */
+ dput(base);
+
+ error = permission(inode, MAY_EXEC);
+ result = ERR_PTR(error);
+ if (error)
+ return result;
+
ino = inode->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
p = find_task_by_pid(pid);
- if (!p) {
- iput(inode);
- return -ENOENT;
- }
- new_inode = NULL;
+ result = ERR_PTR(-ENOENT);
+ if (!p)
+ return result;
+
switch (ino) {
case PROC_PID_CWD:
- if (!p->fs)
+ if (!p->fs || !p->fs->pwd)
break;
- new_inode = p->fs->pwd;
+ result = dget(p->fs->pwd);
break;
+
case PROC_PID_ROOT:
- if (!p->fs)
+ if (!p->fs || !p->fs->root)
break;
- new_inode = p->fs->root;
+ result = dget(p->fs->root);
break;
+
case PROC_PID_EXE: {
struct vm_area_struct * vma;
if (!p->mm)
break;
vma = p->mm->mmap;
while (vma) {
- if (vma->vm_flags & VM_EXECUTABLE) {
- new_inode = vma->vm_inode;
- break;
- }
+ if (vma->vm_flags & VM_EXECUTABLE)
+ return dget(vma->vm_dentry);
+
vma = vma->vm_next;
}
break;
@@ -122,45 +116,38 @@ static int proc_follow_link(struct inode * dir, struct inode * inode,
if (!p->files)
break;
ino &= 0xff;
- if (ino < NR_OPEN && p->files->fd[ino]) {
- new_inode = p->files->fd[ino]->f_inode;
- }
+ if (ino >= NR_OPEN)
+ break;
+ if (!p->files->fd[ino])
+ break;
+ if (!p->files->fd[ino]->f_dentry)
+ break;
+ result = dget(p->files->fd[ino]->f_dentry);
break;
}
}
- iput(inode);
- if (!new_inode)
- return -ENOENT;
- *res_inode = new_inode;
- atomic_inc(&new_inode->i_count);
- return 0;
+ return result;
}
static int proc_readlink(struct inode * inode, char * buffer, int buflen)
{
- int error = proc_follow_link(NULL, inode, 0, 0, &inode);
+ int error;
+ struct dentry * dentry = proc_follow_link(inode, NULL);
- if (error)
- return error;
- if (!inode)
- return -EIO;
-
- /* This will return *one* of the alias names (which is not quite
- * correct). I have to rethink the problem, so this is only a
- * quick hack...
- */
- if(inode->i_dentry) {
- char * tmp = (char*)__get_free_page(GFP_KERNEL);
- int len = d_path(inode->i_dentry, current->fs->root, tmp);
- int min = buflen<PAGE_SIZE ? buflen : PAGE_SIZE;
- if(len <= min)
- min = len+1;
- copy_to_user(buffer, tmp, min);
- free_page((unsigned long)tmp);
- error = len;
- } else {
- error= -ENOENT;
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ error = -ENOENT;
+ if (dentry) {
+ char * tmp = (char*)__get_free_page(GFP_KERNEL);
+ int len = d_path(dentry, current->fs->root, tmp);
+ int min = buflen<PAGE_SIZE ? buflen : PAGE_SIZE;
+ if(len <= min)
+ min = len+1;
+ dput(dentry);
+ copy_to_user(buffer, tmp, min);
+ free_page((unsigned long)tmp);
+ error = len;
+ }
}
- iput(inode);
return error;
}
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index a64ead624..97acb5ee8 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -328,6 +328,7 @@ struct inode_operations proc_mem_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/net.c b/fs/proc/net.c
index 3bc5c339c..257487569 100644
--- a/fs/proc/net.c
+++ b/fs/proc/net.c
@@ -111,6 +111,7 @@ struct inode_operations proc_net_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/omirr.c b/fs/proc/omirr.c
index 0e6377fb2..041e493d2 100644
--- a/fs/proc/omirr.c
+++ b/fs/proc/omirr.c
@@ -7,7 +7,6 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/fs.h>
-#include <linux/dalloc.h>
#include <linux/omirr.h>
#include <asm/uaccess.h>
@@ -288,6 +287,7 @@ struct inode_operations proc_omirr_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c
index 7d741cfaf..346e72ed1 100644
--- a/fs/proc/openpromfs.c
+++ b/fs/proc/openpromfs.c
@@ -1,7 +1,7 @@
-/* $Id: openpromfs.c,v 1.15 1997/06/05 01:28:11 davem Exp $
+/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <linux/module.h>
@@ -68,7 +68,7 @@ static long nodenum_read(struct inode *inode, struct file *file,
if (count < 0 || !inode->u.generic_ip)
return -EINVAL;
- sprintf (buffer, "%8.8x\n", (u32)(inode->u.generic_ip));
+ sprintf (buffer, "%8.8x\n", (u32)(long)(inode->u.generic_ip));
if (file->f_pos >= 9)
return 0;
if (count > 9 - file->f_pos)
@@ -86,27 +86,28 @@ static long property_read(struct inode *inode, struct file *filp,
char *p;
u32 *q;
openprom_property *op;
+ char buffer[64];
if (filp->f_pos >= 0xffffff)
return -EINVAL;
if (!filp->private_data) {
- node = nodes[(u16)((uint)inode->u.generic_ip)].node;
- i = ((u32)inode->u.generic_ip) >> 16;
- if ((u16)((uint)inode->u.generic_ip) == aliases) {
+ node = nodes[(u16)((long)inode->u.generic_ip)].node;
+ i = ((u32)(long)inode->u.generic_ip) >> 16;
+ if ((u16)((long)inode->u.generic_ip) == aliases) {
if (i >= aliases_nodes)
p = 0;
else
p = alias_names [i];
} else
- for (p = prom_firstprop (node);
+ for (p = prom_firstprop (node, buffer);
i && p && *p;
- p = prom_nextprop (node, p), i--)
+ p = prom_nextprop (node, p, buffer), i--)
/* nothing */ ;
if (!p || !*p)
return -EIO;
i = prom_getproplen (node, p);
if (i < 0) {
- if ((u16)((uint)inode->u.generic_ip) == aliases)
+ if ((u16)((long)inode->u.generic_ip) == aliases)
i = 0;
else
return -EIO;
@@ -155,7 +156,7 @@ static long property_read(struct inode *inode, struct file *filp,
if (count > i - k) count = i - k;
if (op->flag & OPP_STRING) {
if (!k) {
- *buf = '\'';
+ __put_user('\'', buf);
k++;
count--;
}
@@ -170,9 +171,9 @@ static long property_read(struct inode *inode, struct file *filp,
k += j;
}
if (count)
- buf [k++ - filp->f_pos] = '\'';
+ __put_user('\'', &buf [k++ - filp->f_pos]);
if (count > 1)
- buf [k++ - filp->f_pos] = '\n';
+ __put_user('\n', &buf [k++ - filp->f_pos]);
} else if (op->flag & OPP_BINARY) {
char buffer[10];
u32 *first, *last;
@@ -186,26 +187,26 @@ static long property_read(struct inode *inode, struct file *filp,
if (first == last) {
sprintf (buffer, "%08x.", *first);
- memcpy (buf, buffer + first_off, last_cnt - first_off);
+ copy_to_user (buf, buffer + first_off, last_cnt - first_off);
buf += last_cnt - first_off;
} else {
for (q = first; q <= last; q++) {
sprintf (buffer, "%08x.", *q);
if (q == first) {
- memcpy (buf, buffer + first_off,
- 9 - first_off);
+ copy_to_user (buf, buffer + first_off,
+ 9 - first_off);
buf += 9 - first_off;
} else if (q == last) {
- memcpy (buf, buffer, last_cnt);
+ copy_to_user (buf, buffer, last_cnt);
buf += last_cnt;
} else {
- memcpy (buf, buffer, 9);
+ copy_to_user (buf, buffer, 9);
buf += 9;
}
}
}
if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9)
- *(buf - 1) = '\n';
+ __put_user('\n', (buf - 1));
k += count;
}
count = k - filp->f_pos;
@@ -242,8 +243,10 @@ static long property_write(struct inode *inode, struct file *filp,
for (i = 0; i < count; i++, j++) {
if (j == 9) j = 0;
if (!j) {
- if (buf [i] != '.') {
- if (buf [i] != '\n') {
+ char ctmp;
+ __get_user(ctmp, &buf[i]);
+ if (ctmp != '.') {
+ if (ctmp != '\n') {
if (op->flag & OPP_BINARY)
return -EINVAL;
else
@@ -255,10 +258,12 @@ static long property_write(struct inode *inode, struct file *filp,
}
}
} else {
- if (buf [i] < '0' ||
- (buf [i] > '9' && buf [i] < 'A') ||
- (buf [i] > 'F' && buf [i] < 'a') ||
- buf [i] > 'f') {
+ char ctmp;
+ __get_user(ctmp, &buf[i]);
+ if (ctmp < '0' ||
+ (ctmp > '9' && ctmp < 'A') ||
+ (ctmp > 'F' && ctmp < 'a') ||
+ ctmp > 'f') {
if (op->flag & OPP_BINARY)
return -EINVAL;
else
@@ -292,8 +297,8 @@ static long property_write(struct inode *inode, struct file *filp,
last_cnt = (k + count) % 9;
if (first + 1 == last) {
memset (tmp, '0', 8);
- memcpy (tmp + first_off, buf, (count + first_off > 8) ?
- 8 - first_off : count);
+ copy_from_user (tmp + first_off, buf,
+ (count + first_off > 8) ? 8 - first_off : count);
mask = 0xffffffff;
mask2 = 0xffffffff;
for (j = 0; j < first_off; j++)
@@ -312,8 +317,8 @@ static long property_write(struct inode *inode, struct file *filp,
if (q == first) {
if (first_off < 8) {
memset (tmp, '0', 8);
- memcpy (tmp + first_off, buf,
- 8 - first_off);
+ copy_from_user (tmp + first_off, buf,
+ 8 - first_off);
mask = 0xffffffff;
for (j = 0; j < first_off; j++)
mask >>= 1;
@@ -324,7 +329,7 @@ static long property_write(struct inode *inode, struct file *filp,
} else if ((q == last - 1) && last_cnt
&& (last_cnt < 8)) {
memset (tmp, '0', 8);
- memcpy (tmp, buf, last_cnt);
+ copy_from_user (tmp, buf, last_cnt);
mask = 0xffffffff;
for (j = 0; j < 8 - last_cnt; j++)
mask <<= 1;
@@ -332,7 +337,10 @@ static long property_write(struct inode *inode, struct file *filp,
*q |= simple_strtoul (tmp, 0, 16);
buf += last_cnt;
} else {
- *q = simple_strtoul (buf, 0, 16);
+ char tchars[17]; /* XXX yuck... */
+
+ copy_from_user(tchars, buf, 16);
+ *q = simple_strtoul (tchars, 0, 16);
buf += 9;
}
}
@@ -347,12 +355,15 @@ static long property_write(struct inode *inode, struct file *filp,
write_try_string:
if (!(op->flag & OPP_BINARY)) {
if (!(op->flag & (OPP_QUOTED | OPP_NOTQUOTED))) {
+ char ctmp;
+
/* No way, if somebody starts writing from the middle,
* we don't know whether he uses quotes around or not
*/
if (k > 0)
return -EINVAL;
- if (*buf == '\'') {
+ __get_user(ctmp, buf);
+ if (ctmp == '\'') {
op->flag |= OPP_QUOTED;
buf++;
count--;
@@ -383,7 +394,7 @@ write_try_string:
kfree (b);
}
p = op->value + filp->f_pos - ((op->flag & OPP_QUOTED) ? 1 : 0);
- memcpy (p, buf, count);
+ copy_from_user (p, buf, count);
op->flag |= OPP_DIRTY;
for (i = 0; i < count; i++, p++)
if (*p == '\n') {
@@ -414,8 +425,8 @@ int property_release (struct inode *inode, struct file *filp)
if (!op)
return 0;
- node = nodes[(u16)((uint)inode->u.generic_ip)].node;
- if ((u16)((uint)inode->u.generic_ip) == aliases) {
+ node = nodes[(u16)((long)inode->u.generic_ip)].node;
+ if ((u16)((long)inode->u.generic_ip) == aliases) {
if ((op->flag & OPP_DIRTY) && (op->flag & OPP_STRING)) {
char *p = op->name;
int i = (op->value - op->name) - strlen (op->name) - 1;
@@ -484,6 +495,7 @@ static struct inode_operations openpromfs_prop_inode_ops = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -516,6 +528,7 @@ static struct inode_operations openpromfs_nodenum_inode_ops = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -548,6 +561,7 @@ static struct inode_operations openprom_alias_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -604,6 +618,7 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
int i;
struct inode *inode;
struct openpromfs_dev *d = NULL;
+ char buffer2[64];
*result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
@@ -659,9 +674,9 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
if (!ino) {
int j = NODEP2INO(NODE(dir->i_ino).first_prop);
if (dirnode != aliases) {
- for (p = prom_firstprop (n);
+ for (p = prom_firstprop (n, buffer2);
p && *p;
- p = prom_nextprop (n, p)) {
+ p = prom_nextprop (n, p, buffer2)) {
j++;
if ((len == strlen (p))
&& !strncmp (p, name, len)) {
@@ -720,7 +735,7 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_op = &openpromfs_nodenum_inode_ops;
inode->i_nlink = 1;
- inode->u.generic_ip = (void *)(n);
+ inode->u.generic_ip = (void *)(long)(n);
break;
case OPFSL_PROPERTY:
if ((dirnode == options) && (len == 17)
@@ -737,7 +752,7 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
inode->i_nlink = 1;
if (inode->i_size < 0)
inode->i_size = 0;
- inode->u.generic_ip = (void *)(((u16)dirnode) |
+ inode->u.generic_ip = (void *)(long)(((u16)dirnode) |
(((u16)(ino - NODEP2INO(NODE(dir->i_ino).first_prop) - 1)) << 16));
break;
case OPFSL_DEVICE:
@@ -761,6 +776,7 @@ static int openpromfs_readdir(struct inode * inode, struct file * filp,
u16 node;
char *p;
struct openpromfs_dev *d;
+ char buffer2[64];
if (!inode || !S_ISDIR (inode->i_mode)) return -ENOTDIR;
ino = inode->i_ino;
@@ -813,9 +829,9 @@ static int openpromfs_readdir(struct inode * inode, struct file * filp,
}
}
} else {
- for (p = prom_firstprop (n);
+ for (p = prom_firstprop (n, buffer2);
p && *p;
- p = prom_nextprop (n, p)) {
+ p = prom_nextprop (n, p, buffer2)) {
j++;
if (i) i--;
else {
@@ -877,7 +893,7 @@ static int openpromfs_create (struct inode *dir, const char *name, int len,
inode->i_op = &openpromfs_prop_inode_ops;
inode->i_nlink = 1;
if (inode->i_size < 0) inode->i_size = 0;
- inode->u.generic_ip = (void *)(((u16)aliases) |
+ inode->u.generic_ip = (void *)(long)(((u16)aliases) |
(((u16)(aliases_nodes - 1)) << 16));
*result = inode;
return 0;
@@ -940,6 +956,7 @@ static u16 get_nodes (u16 parent, u32 node)
{
char *p;
u16 n = last_node++, i;
+ char buffer[64];
if (check_space (n) < 0)
return 0xffff;
@@ -961,15 +978,15 @@ static u16 get_nodes (u16 parent, u32 node)
}
}
if (n != aliases)
- for (p = prom_firstprop (node);
+ for (p = prom_firstprop (node, buffer);
p && p != (char *)-1 && *p;
- p = prom_nextprop (node, p))
+ p = prom_nextprop (node, p, buffer))
first_prop++;
else {
char *q;
- for (p = prom_firstprop (node);
+ for (p = prom_firstprop (node, buffer);
p && p != (char *)-1 && *p;
- p = prom_nextprop (node, p)) {
+ p = prom_nextprop (node, p, buffer)) {
if (aliases_nodes == ALIASES_NNODES)
break;
for (i = 0; i < aliases_nodes; i++)
@@ -1012,7 +1029,7 @@ void openpromfs_use (struct inode *inode, int inc)
static int usec = 0;
if (inc) {
- if (atomic_read(&inode->i_count) == 1)
+ if (inode->i_count == 1)
usec++;
else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
root_fresh = 0;
@@ -1025,10 +1042,10 @@ void openpromfs_use (struct inode *inode, int inc)
usec--;
}
printk ("openpromfs_use: %d %d %d %d\n",
- inode->i_ino, inc, usec, atomic_read(&inode->i_count));
+ inode->i_ino, inc, usec, inode->i_count);
#else
if (inc) {
- if (atomic_read(&inode->i_count) == 1)
+ if (inode->i_count == 1)
MOD_INC_USE_COUNT;
else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
root_fresh = 0;
@@ -1059,8 +1076,10 @@ EXPORT_NO_SYMBOLS;
int init_module (void)
#endif
{
+#ifndef __sparc_v9__
if (!romvec->pv_romvers)
return RET(ENODEV);
+#endif
nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0, 0);
if (!nodes) {
printk (KERN_WARNING "/proc/openprom: can't get free page\n");
diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c
index 71c29dd75..d3077ea79 100644
--- a/fs/proc/procfs_syms.c
+++ b/fs/proc/procfs_syms.c
@@ -38,7 +38,7 @@ EXPORT_SYMBOL(proc_openprom_deregister);
static struct file_system_type proc_fs_type = {
"proc",
- FS_NO_DCACHE,
+ 0 /* FS_NO_DCACHE doesn't work correctly */,
proc_read_super,
NULL
};
diff --git a/fs/proc/root.c b/fs/proc/root.c
index f42557d2c..2b456ca57 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -24,7 +24,7 @@
#define FIRST_PROCESS_ENTRY 256
static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
-static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
+static int proc_root_lookup(struct inode *,struct dentry *);
static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
@@ -64,6 +64,7 @@ struct inode_operations proc_dir_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -104,6 +105,7 @@ static struct inode_operations proc_root_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -149,14 +151,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 inode *, struct file *, void *, filldir_t);
-static int (*proc_openprom_deflookup_ptr)(struct inode *, const char *, int, struct inode **);
+static int (*proc_openprom_deflookup_ptr)(struct inode *, struct qstr *, struct inode **);
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 inode *, struct file *, void *, filldir_t),
- int (*lookup)(struct inode *, const char *, int, struct inode **),
+ int (*lookup)(struct inode *, struct qstr *, struct inode **),
void (*use)(struct inode *, int),
struct openpromfs_dev ***devices)
{
@@ -218,15 +220,13 @@ proc_openprom_defreaddir(struct inode * inode, struct file * filp,
}
static int
-proc_openprom_deflookup(struct inode * dir,const char * name, int len,
- struct inode ** result)
+proc_openprom_deflookup(struct inode * dir, struct qstr *str, struct inode ** result)
{
request_module("openpromfs");
if (proc_openprom_inode_operations.lookup !=
proc_openprom_deflookup)
return proc_openprom_inode_operations.lookup
- (dir, name, len, result);
- iput(dir);
+ (dir, str, result);
return -ENOENT;
}
#endif
@@ -264,6 +264,7 @@ struct inode_operations proc_openprom_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -350,7 +351,6 @@ static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
int len;
char tmp[30];
- iput(inode);
len = sprintf(tmp, "%d", current->pid);
if (buflen < len)
len = buflen;
@@ -358,6 +358,15 @@ static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
return len;
}
+static struct dentry * proc_self_follow_link(struct inode *inode, struct dentry *base)
+{
+ int len;
+ char tmp[30];
+
+ len = sprintf(tmp, "%d", current->pid);
+ return lookup_dentry(tmp, base, 1);
+}
+
static struct inode_operations proc_self_inode_operations = {
NULL, /* no file-ops */
NULL, /* create */
@@ -370,6 +379,7 @@ static struct inode_operations proc_self_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
proc_self_readlink, /* readlink */
+ proc_self_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -611,93 +621,49 @@ void proc_root_init(void)
proc_tty_init();
}
-
-int proc_match(int len,const char * name,struct proc_dir_entry * de)
-{
- if (!de || !de->low_ino)
- return 0;
- /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
- if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
- return 1;
- if (de->namelen != len)
- return 0;
- return !memcmp(name, de->name, len);
-}
-
-int proc_lookup(struct inode * dir,const char * name, int len,
- struct inode ** result)
+/*
+ * Don't create negative dentries here, return -ENOENT by hand
+ * instead.
+ */
+int proc_lookup(struct inode * dir, struct dentry *dentry)
{
+ struct inode *inode;
struct proc_dir_entry * de;
- int ino;
- *result = NULL;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- iput(dir);
+ if (!dir || !S_ISDIR(dir->i_mode))
return -ENOTDIR;
- }
de = (struct proc_dir_entry *) dir->u.generic_ip;
- if (!de) {
- iput(dir);
- return -EINVAL;
- }
-
- /* Either remove this as soon as possible due to security problems,
- * or uncomment the root-only usage.
- */
-
- /* Allow generic inode lookups everywhere.
- * No other name in /proc must begin with a '['.
- */
- if(/*!current->uid &&*/ name[0] == '[')
- return proc_arbitrary_lookup(dir,name,len,result);
-
- /* Special case "." and "..": they aren't on the directory list */
- *result = dir;
- if (!len)
- return 0;
- if (name[0] == '.') {
- if (len == 1)
- return 0;
- if (name[1] == '.' && len == 2) {
- struct inode * inode;
- inode = proc_get_inode(dir->i_sb, de->parent->low_ino, de->parent);
- iput(dir);
- if (!inode)
- return -EINVAL;
- *result = inode;
- return 0;
+ inode = NULL;
+ if (de) {
+ for (de = de->subdir; de ; de = de->next) {
+ if (!de || !de->low_ino)
+ continue;
+ if (de->namelen != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
+ int ino = de->low_ino | (dir->i_ino & ~(0xffff));
+ inode = proc_get_inode(dir->i_sb, ino, de);
+ if (!inode)
+ return -EINVAL;
+ break;
+ }
}
}
-
- *result = NULL;
- for (de = de->subdir; de ; de = de->next) {
- if (proc_match(len, name, de))
- break;
- }
- if (!de) {
- iput(dir);
+ if (!inode)
return -ENOENT;
- }
- ino = de->low_ino | (dir->i_ino & ~(0xffff));
-
- if (!(*result = proc_get_inode(dir->i_sb, ino, de))) {
- iput(dir);
- return -EINVAL;
- }
- iput(dir);
+ d_add(dentry, inode);
return 0;
}
-static int proc_root_lookup(struct inode * dir,const char * name, int len,
- struct inode ** result)
+static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
{
unsigned int pid, c;
- int ino, retval;
struct task_struct *p;
-
- atomic_inc(&dir->i_count);
+ const char *name;
+ struct inode *inode;
+ int len;
if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
dir->i_nlink = proc_root.nlink;
@@ -710,13 +676,12 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len,
read_unlock(&tasklist_lock);
}
- retval = proc_lookup(dir, name, len, result);
- if (retval != -ENOENT) {
- iput(dir);
- return retval;
- }
+ if (!proc_lookup(dir, dentry))
+ return 0;
pid = 0;
+ name = dentry->d_name.name;
+ len = dentry->d_name.len;
while (len-- > 0) {
c = *name - '0';
name++;
@@ -732,16 +697,14 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len,
}
}
p = find_task_by_pid(pid);
- if (!pid || !p) {
- iput(dir);
- return -ENOENT;
- }
- ino = (pid << 16) + PROC_PID_INO;
- if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid))) {
- iput(dir);
- return -EINVAL;
+ inode = NULL;
+ if (pid && p) {
+ unsigned long ino = (pid << 16) + PROC_PID_INO;
+ inode = proc_get_inode(dir->i_sb, ino, &proc_pid);
+ if (!inode)
+ return -EINVAL;
}
- iput(dir);
+ d_add(dentry, inode);
return 0;
}
diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c
index fd629a75c..b1e77398c 100644
--- a/fs/proc/scsi.c
+++ b/fs/proc/scsi.c
@@ -69,6 +69,7 @@ struct inode_operations proc_scsi_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/read_write.c b/fs/read_write.c
index 81b19ac30..6c422b7f4 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -60,13 +60,15 @@ asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
{
long retval;
struct file * file;
+ struct dentry * dentry;
struct inode * inode;
lock_kernel();
retval = -EBADF;
if (fd >= NR_OPEN ||
!(file = current->files->fd[fd]) ||
- !(inode = file->f_inode))
+ !(dentry = file->f_dentry) ||
+ !(inode = dentry->d_inode))
goto bad;
retval = -EINVAL;
if (origin > 2)
@@ -83,6 +85,7 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
{
long retval;
struct file * file;
+ struct dentry * dentry;
struct inode * inode;
long long offset;
@@ -90,7 +93,8 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
retval = -EBADF;
if (fd >= NR_OPEN ||
!(file = current->files->fd[fd]) ||
- !(inode = file->f_inode))
+ !(dentry = file->f_dentry) ||
+ !(inode = dentry->d_inode))
goto bad;
retval = -EINVAL;
if (origin > 2)
@@ -115,6 +119,7 @@ asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count)
{
int error;
struct file * file;
+ struct dentry * dentry;
struct inode * inode;
long (*read)(struct inode *, struct file *, char *, unsigned long);
@@ -123,7 +128,10 @@ asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count)
file = fget(fd);
if (!file)
goto bad_file;
- inode = file->f_inode;
+ dentry = file->f_dentry;
+ if (!dentry)
+ goto bad_file;
+ inode = dentry->d_inode;
if (!inode)
goto out;
error = -EBADF;
@@ -137,7 +145,7 @@ asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count)
goto out;
error = read(inode,file,buf,count);
out:
- fput(file, inode);
+ fput(file);
bad_file:
unlock_kernel();
return error;
@@ -147,6 +155,7 @@ asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count
{
int error;
struct file * file;
+ struct dentry * dentry;
struct inode * inode;
long (*write)(struct inode *, struct file *, const char *, unsigned long);
@@ -155,7 +164,10 @@ asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count
file = fget(fd);
if (!file)
goto bad_file;
- inode = file->f_inode;
+ dentry = file->f_dentry;
+ if (!dentry)
+ goto out;
+ inode = dentry->d_inode;
if (!inode)
goto out;
if (!(file->f_mode & 2))
@@ -168,10 +180,9 @@ asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count
goto out;
down(&inode->i_sem);
error = write(inode,file,buf,count);
- inode->i_status |= ST_MODIFIED;
up(&inode->i_sem);
out:
- fput(file, inode);
+ fput(file);
bad_file:
unlock_kernel();
return error;
@@ -264,8 +275,6 @@ static long do_readv_writev(int type, struct inode * inode, struct file * file,
if (nr != len)
break;
}
- if(fn == (IO_fn_t) file->f_op->write)
- inode->i_status |= ST_MODIFIED;
if (iov != iovstack)
kfree(iov);
return retval;
@@ -274,14 +283,30 @@ static long do_readv_writev(int type, struct inode * inode, struct file * file,
asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count)
{
struct file * file;
+ struct dentry * dentry;
struct inode * inode;
- long err = -EBADF;
+ long err;
lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+ err = -EBADF;
+ if (fd >= NR_OPEN)
+ goto out;
+
+ file = current->files->fd[fd];
+ if (!file)
goto out;
+
if (!(file->f_mode & 1))
goto out;
+
+ dentry = file->f_dentry;
+ if (!dentry)
+ goto out;
+
+ inode = dentry->d_inode;
+ if (!inode)
+ goto out;
+
err = do_readv_writev(VERIFY_WRITE, inode, file, vector, count);
out:
unlock_kernel();
@@ -290,15 +315,32 @@ out:
asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count)
{
- int error = -EBADF;
+ long error;
struct file * file;
+ struct dentry * dentry;
struct inode * inode;
lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+ error = -EBADF;
+
+ if (fd >= NR_OPEN)
+ goto out;
+
+ file = current->files->fd[fd];
+ if (!file)
goto out;
+
if (!(file->f_mode & 2))
goto out;
+
+ dentry = file->f_dentry;
+ if (!dentry)
+ goto out;
+
+ inode = dentry->d_inode;
+ if (!inode)
+ goto out;
+
down(&inode->i_sem);
error = do_readv_writev(VERIFY_READ, inode, file, vector, count);
up(&inode->i_sem);
diff --git a/fs/readdir.c b/fs/readdir.c
index a86398ac3..2a2b0a707 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -1,35 +1,20 @@
/*
- * fs/readdir.c
+ * linux/fs/readdir.c
*
* Copyright (C) 1995 Linus Torvalds
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#ifdef CONFIG_TRANS_NAMES
-#include <linux/nametrans.h>
-#endif
-#include <linux/dalloc.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
-/* [T.Schoebel-Theuer] I am assuming that directories never get too large.
- * The problem is that getdents() delivers d_offset's that can be used
- * for lseek() by the user, so I must encode the status information for
- * name translation and dcache baskets in the offset.
- * Note that the linux man page getdents(2) does not mention that
- * the d_offset is fs-specific and can be used for lseek().
- */
-#define BASKET_BIT (1<<30) /* 31 is already used by affs */
-#define TRANS_BIT (1<<29)
-
/*
* Traditional linux readdir() handling..
*
@@ -50,9 +35,6 @@ struct old_linux_dirent {
struct readdir_callback {
struct old_linux_dirent * dirent;
- struct file * file;
- int translate;
- off_t oldoffset;
int count;
};
@@ -65,60 +47,49 @@ static int fillonedir(void * __buf, const char * name, int namlen, off_t offset,
return -EINVAL;
buf->count++;
dirent = buf->dirent;
- copy_to_user(dirent->d_name, name, namlen);
- put_user(0, dirent->d_name + namlen);
-#ifdef CONFIG_TRANS_NAMES
- if(!buf->translate) {
- char * cut;
-#ifdef CONFIG_TRANS_RESTRICT
- struct inode * inode = buf->file->f_inode;
- cut = testname(inode && inode->i_gid != CONFIG_TRANS_GID, dirent->d_name);
-#else
- cut = testname(1, dirent->d_name);
-#endif
- if(cut) {
- put_user(0, cut);
- buf->translate = 1;
- }
- }
-#endif
put_user(ino, &dirent->d_ino);
put_user(offset, &dirent->d_offset);
put_user(namlen, &dirent->d_namlen);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
return 0;
}
asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
{
- int error = -EBADF;
+ int error;
struct file * file;
+ struct dentry * dentry;
+ struct inode * inode;
struct readdir_callback buf;
- off_t oldpos;
lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ error = -EBADF;
+ if (fd >= NR_OPEN)
goto out;
- error = -ENOTDIR;
- if (!file->f_op || !file->f_op->readdir)
+
+ file = current->files->fd[fd];
+ if (!file)
goto out;
- error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent));
- if (error)
+
+ dentry = file->f_dentry;
+ if (!dentry)
goto out;
- oldpos = file->f_pos;
- buf.file = file;
- buf.dirent = dirent;
+
+ inode = dentry->d_inode;
+ if (!inode)
+ goto out;
+
buf.count = 0;
- buf.translate = 0;
- if(file->f_pos & TRANS_BIT) {
- file->f_pos &= ~TRANS_BIT;
- buf.translate = 1;
- }
- error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
+ buf.dirent = dirent;
+
+ error = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdir)
+ goto out;
+
+ error = file->f_op->readdir(inode, file, &buf, fillonedir);
if (error < 0)
goto out;
- if(buf.translate) {
- file->f_pos = oldpos | TRANS_BIT;
- }
error = buf.count;
out:
unlock_kernel();
@@ -139,11 +110,8 @@ struct linux_dirent {
struct getdents_callback {
struct linux_dirent * current_dir;
struct linux_dirent * previous;
- struct file * file;
int count;
- int error;
- int restricted;
- int do_preload;
+ int error;
};
static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
@@ -152,51 +120,18 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
struct getdents_callback * buf = (struct getdents_callback *) __buf;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
- /* Do not touch buf->error any more if everything is ok! */
+ buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
- return (buf->error = -EINVAL);
-#ifdef CONFIG_DCACHE_PRELOAD
- if(buf->do_preload && (name[0] != '.' || namlen > 2)) {
- struct qstr qname = { name, namlen };
- struct inode * dir = buf->file->f_inode;
- d_entry_preliminary(dir->i_dentry, &qname, ino);
- }
-#endif
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent)
+ put_user(offset, &dirent->d_off);
dirent = buf->current_dir;
- copy_to_user(dirent->d_name, name, namlen);
- put_user(0, dirent->d_name + namlen);
-#ifdef CONFIG_TRANS_NAMES
- {
- char * cut;
-#ifdef CONFIG_TRANS_RESTRICT
- cut = testname(buf->restricted, dirent->d_name);
-#else
- cut = testname(1, dirent->d_name);
-#endif
- if(cut) {
- int newlen = (int)cut - (int)dirent->d_name;
- int newreclen = ROUND_UP(NAME_OFFSET(dirent) + newlen + 1);
- /* Either both must fit or none. This way we need
- * no status information in f_pos */
- if (reclen+newlen > buf->count)
- return -EINVAL;
- put_user(0, cut);
- put_user(ino, &dirent->d_ino);
- put_user(newreclen, &dirent->d_reclen);
- put_user(offset, &dirent->d_off);
- ((char *) dirent) += newreclen;
- buf->count -= newreclen;
- put_user(offset, &dirent->d_off);
- copy_to_user(dirent->d_name, name, namlen);
- put_user(0, dirent->d_name + namlen);
- }
- }
-#endif
+ buf->previous = dirent;
put_user(ino, &dirent->d_ino);
put_user(reclen, &dirent->d_reclen);
- if (buf->previous)
- put_user(buf->file->f_pos, &buf->previous->d_off);
- buf->previous = dirent;
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
((char *) dirent) += reclen;
buf->current_dir = dirent;
buf->count -= reclen;
@@ -206,84 +141,45 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
{
struct file * file;
+ struct dentry * dentry;
+ struct inode * inode;
+ struct linux_dirent * lastdirent;
struct getdents_callback buf;
- int error = -EBADF;
+ int error;
lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ error = -EBADF;
+ if (fd >= NR_OPEN)
goto out;
- error = -ENOTDIR;
- if (!file->f_op || !file->f_op->readdir)
+
+ file = current->files->fd[fd];
+ if (!file)
goto out;
- error = verify_area(VERIFY_WRITE, dirent, count);
- if (error)
+
+ dentry = file->f_dentry;
+ if (!dentry)
goto out;
- buf.file = file;
+
+ inode = dentry->d_inode;
+ if (!inode)
+ goto out;
+
buf.current_dir = (struct linux_dirent *) dirent;
buf.previous = NULL;
buf.count = count;
buf.error = 0;
- buf.restricted = 0;
-#ifdef CONFIG_TRANS_RESTRICT
- buf.restricted = file->f_inode && file->f_inode->i_gid != CONFIG_TRANS_GID;
-#endif
- buf.do_preload = 0;
-#ifdef CONFIG_DCACHE_PRELOAD
- if(file->f_inode && file->f_inode->i_dentry &&
- !(file->f_inode->i_sb->s_type->fs_flags & (FS_NO_DCACHE|FS_NO_PRELIM)) &&
- !(file->f_inode->i_dentry->d_flag & D_PRELOADED))
- buf.do_preload = 1;
-#endif
-
- if(!(file->f_pos & BASKET_BIT)) {
- int oldcount;
- do {
- oldcount = buf.count;
- error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
- if (error < 0)
- goto out;
- } while(!buf.error && buf.count != oldcount);
- }
- if(!buf.error) {
- int nr = 0;
- struct dentry * list = file->f_inode ?
- d_basket(file->f_inode->i_dentry) : NULL;
- struct dentry * ptr = list;
-#ifdef CONFIG_DCACHE_PRELOAD
- if(buf.do_preload) {
- buf.do_preload = 0;
- file->f_inode->i_dentry->d_flag |= D_PRELOADED;
- }
-#endif
- if(ptr) {
- if(!(file->f_pos & BASKET_BIT))
- file->f_pos = BASKET_BIT;
- do {
- struct dentry * next = ptr->d_basket_next;
- struct inode * inode;
- /* vfs_locks() are missing here */
- inode = d_inode(&ptr);
- if(inode) {
- nr++;
- if(nr > (file->f_pos & ~BASKET_BIT)) {
- int err = filldir(&buf, ptr->d_name,
- ptr->d_len,
- file->f_pos,
- inode->i_ino);
- if(err)
- break;
- file->f_pos++;
- }
- iput(inode);
- }
- ptr = next;
- } while(ptr != list);
- }
- }
- if (!buf.previous) {
- error = buf.error;
- } else {
- put_user(file->f_pos, &buf.previous->d_off);
+
+ error = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdir)
+ goto out;
+
+ error = file->f_op->readdir(inode, file, &buf, filldir);
+ if (error < 0)
+ goto out;
+ lastdirent = buf.previous;
+ error = buf.error;
+ if (lastdirent) {
+ put_user(file->f_pos, &lastdirent->d_off);
error = count - buf.count;
}
out:
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 0ddda855d..5d936ee59 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -584,7 +584,7 @@ static struct super_operations romfs_ops = {
static struct file_system_type romfs_fs_type = {
"romfs",
- (FS_REQUIRES_DEV | FS_NO_DCACHE), /* Can dcache be used? */
+ FS_REQUIRES_DEV,
romfs_read_super,
NULL
};
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 20738b0d2..75d3dbff7 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -431,7 +431,7 @@ int smb_current_vmalloced;
static struct file_system_type smb_fs_type = {
"smbfs",
- FS_NO_DCACHE,
+ 0 /* FS_NO_DCACHE doesn't work correctly */,
smb_read_super,
NULL
};
diff --git a/fs/smbfs/mmap.c b/fs/smbfs/mmap.c
index 472fad6de..20a2d0569 100644
--- a/fs/smbfs/mmap.c
+++ b/fs/smbfs/mmap.c
@@ -119,8 +119,8 @@ smb_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma)
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
- vma->vm_inode = inode;
- atomic_inc(&inode->i_count);
+
+ vma->vm_dentry = dget(file->f_dentry);
vma->vm_ops = &smb_file_mmap;
return 0;
}
diff --git a/fs/stat.c b/fs/stat.c
index 03f685552..b17c6bb13 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -48,8 +48,6 @@ static int cp_old_stat(struct inode * inode, struct __old_kernel_stat * statbuf)
tmp.st_gid = inode->i_gid;
tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
tmp.st_size = inode->i_size;
- if (inode->i_pipe)
- tmp.st_size = PIPE_SIZE(*inode);
tmp.st_atime = inode->i_atime;
tmp.st_mtime = inode->i_mtime;
tmp.st_ctime = inode->i_ctime;
@@ -72,8 +70,6 @@ static int cp_new_stat(struct inode * inode, struct stat * statbuf)
tmp.st_gid = inode->i_gid;
tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
tmp.st_size = inode->i_size;
- if (inode->i_pipe)
- tmp.st_size = PIPE_SIZE(*inode);
tmp.st_atime = inode->i_atime;
tmp.st_mtime = inode->i_mtime;
tmp.st_ctime = inode->i_ctime;
@@ -116,6 +112,7 @@ static int cp_new_stat(struct inode * inode, struct stat * statbuf)
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
}
+
#if !defined(__alpha__) && !defined(__sparc__)
/*
* For backward compatibility? Maybe this should be moved
@@ -123,17 +120,21 @@ static int cp_new_stat(struct inode * inode, struct stat * statbuf)
*/
asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf)
{
- struct inode * inode;
+ struct dentry * dentry;
int error;
lock_kernel();
- error = namei(NAM_FOLLOW_LINK, filename, &inode);
- if (error)
- goto out;
- if ((error = do_revalidate(inode)) == 0)
- error = cp_old_stat(inode,statbuf);
- iput(inode);
-out:
+ dentry = namei(filename);
+
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+ error = do_revalidate(inode);
+ if (!error)
+ error = cp_old_stat(inode, statbuf);
+
+ dput(dentry);
+ }
unlock_kernel();
return error;
}
@@ -141,17 +142,21 @@ out:
asmlinkage int sys_newstat(char * filename, struct stat * statbuf)
{
- struct inode * inode;
+ struct dentry * dentry;
int error;
lock_kernel();
- error = namei(NAM_FOLLOW_LINK, filename, &inode);
- if (error)
- goto out;
- if ((error = do_revalidate(inode)) == 0)
- error = cp_new_stat(inode,statbuf);
- iput(inode);
-out:
+ dentry = namei(filename);
+
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+ error = do_revalidate(inode);
+ if (!error)
+ error = cp_new_stat(inode,statbuf);
+
+ dput(dentry);
+ }
unlock_kernel();
return error;
}
@@ -164,17 +169,21 @@ out:
*/
asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
{
- struct inode * inode;
+ struct dentry * dentry;
int error;
lock_kernel();
- error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
- if (error)
- goto out;
- if ((error = do_revalidate(inode)) == 0)
- error = cp_old_stat(inode,statbuf);
- iput(inode);
-out:
+ dentry = lnamei(filename);
+
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+ error = do_revalidate(inode);
+ if (!error)
+ error = cp_old_stat(inode, statbuf);
+
+ dput(dentry);
+ }
unlock_kernel();
return error;
}
@@ -183,17 +192,21 @@ out:
asmlinkage int sys_newlstat(char * filename, struct stat * statbuf)
{
- struct inode * inode;
+ struct dentry * dentry;
int error;
lock_kernel();
- error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
- if (error)
- goto out;
- if ((error = do_revalidate(inode)) == 0)
- error = cp_new_stat(inode,statbuf);
- iput(inode);
-out:
+ dentry = lnamei(filename);
+
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+ error = do_revalidate(inode);
+ if (!error)
+ error = cp_new_stat(inode,statbuf);
+
+ dput(dentry);
+ }
unlock_kernel();
return error;
}
@@ -207,17 +220,19 @@ out:
asmlinkage int sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
{
struct file * f;
- struct inode * inode;
- int ret = -EBADF;
+ int err = -EBADF;
lock_kernel();
- if (fd >= NR_OPEN || !(f=current->files->fd[fd]) || !(inode=f->f_inode))
- goto out;
- if ((ret = do_revalidate(inode)) == 0)
- ret = cp_old_stat(inode,statbuf);
-out:
+ if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) {
+ struct dentry * dentry = f->f_dentry;
+ struct inode * inode = dentry->d_inode;
+
+ err = do_revalidate(inode);
+ if (!err)
+ err = cp_old_stat(inode,statbuf);
+ }
unlock_kernel();
- return ret;
+ return err;
}
#endif
@@ -225,45 +240,43 @@ out:
asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf)
{
struct file * f;
- struct inode * inode;
int err = -EBADF;
lock_kernel();
- if (fd >= NR_OPEN || !(f=current->files->fd[fd]) || !(inode=f->f_inode))
- goto out;
- if ((err = do_revalidate(inode)) == 0)
- err = cp_new_stat(inode,statbuf);
-out:
+ if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) {
+ struct dentry * dentry = f->f_dentry;
+ struct inode * inode = dentry->d_inode;
+
+ err = do_revalidate(inode);
+ if (!err)
+ err = cp_new_stat(inode,statbuf);
+ }
unlock_kernel();
return err;
}
asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
{
- struct inode * inode;
- int error = -EINVAL;
+ struct dentry * dentry;
+ int error;
- lock_kernel();
if (bufsiz <= 0)
- goto out;
- error = verify_area(VERIFY_WRITE,buf,bufsiz);
- if (error)
- goto out;
- error = namei(NAM_FOLLOW_TRAILSLASH, path, &inode);
- if (error)
- goto out;
- error = -EINVAL;
- if (!inode->i_op || !inode->i_op->readlink ||
- !S_ISLNK(inode->i_mode) || (error = do_revalidate(inode)) < 0) {
- iput(inode);
- goto out;
- }
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ return -EINVAL;
+
+ lock_kernel();
+ dentry = lnamei(path);
+
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+
+ error = -EINVAL;
+ if (inode->i_op && inode->i_op->readlink && !(error = do_revalidate(inode))) {
+ UPDATE_ATIME(inode);
+ error = inode->i_op->readlink(inode,buf,bufsiz);
+ }
+ dput(dentry);
}
- error = inode->i_op->readlink(inode,buf,bufsiz);
-out:
unlock_kernel();
return error;
}
diff --git a/fs/super.c b/fs/super.c
index ec47301aa..f143f9348 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -33,7 +33,6 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/fd.h>
-#include <linux/dalloc.h>
#include <linux/init.h>
#include <asm/system.h>
@@ -102,13 +101,13 @@ struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_na
lptr->mnt_dev = dev;
sema_init(&lptr->mnt_sem, 1);
- if (dev_name && !getname(dev_name, &tmp)) {
+ if (dev_name && !IS_ERR(tmp = getname(dev_name))) {
if ((lptr->mnt_devname =
(char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
strcpy(lptr->mnt_devname, tmp);
putname(tmp);
}
- if (dir_name && !getname(dir_name, &tmp)) {
+ if (dir_name && !IS_ERR(tmp = getname(dir_name))) {
if ((lptr->mnt_dirname =
(char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
strcpy(lptr->mnt_dirname, tmp);
@@ -198,9 +197,11 @@ static int fs_index(const char * __name)
char * name;
int err, index;
- err = getname(__name, &name);
- if (err)
+ name = getname(__name);
+ err = PTR_ERR(name);
+ if (IS_ERR(name))
return err;
+
index = 0;
for (tmp = file_systems ; tmp ; tmp = tmp->next) {
if (strcmp(tmp->name, name) == 0) {
@@ -454,26 +455,6 @@ struct super_block * get_super(kdev_t dev)
return NULL;
}
-void put_super(kdev_t dev)
-{
- struct super_block * sb;
-
- if (dev == ROOT_DEV) {
- printk("VFS: Root device %s: prepare for armageddon\n",
- kdevname(dev));
- return;
- }
- if (!(sb = get_super(dev)))
- return;
- if (sb->s_covered) {
- printk("VFS: Mounted device %s - tssk, tssk\n",
- kdevname(dev));
- return;
- }
- if (sb->s_op && sb->s_op->put_super)
- sb->s_op->put_super(sb);
-}
-
asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf)
{
struct super_block *s;
@@ -535,7 +516,6 @@ static struct super_block * read_super(kdev_t dev,const char *name,int flags,
return NULL;
}
s->s_dev = dev;
- s->s_covered = NULL;
s->s_rd_only = 0;
s->s_dirt = 0;
s->s_type = type;
@@ -570,18 +550,45 @@ void put_unnamed_dev(kdev_t dev)
kdevname(dev));
}
+static void d_umount(struct dentry *dentry)
+{
+ struct dentry * covers = dentry->d_covers;
+
+ if (covers != dentry) {
+ covers->d_mounts = covers;
+ dentry->d_covers = dentry;
+ dput(covers);
+ dput(dentry);
+ }
+}
+
+static void d_mount(struct dentry *covers, struct dentry *dentry)
+{
+ if (covers->d_mounts != covers) {
+ printk("VFS: mount - already mounted\n");
+ return;
+ }
+ covers->d_mounts = dentry;
+ dentry->d_covers = covers;
+}
+
static int do_umount(kdev_t dev,int unmount_root)
{
struct super_block * sb;
int retval;
+ sb = get_super(dev);
+ if (!sb)
+ return -ENOENT;
+
+ if (!sb->s_root)
+ return -ENOENT;
+
if (dev==ROOT_DEV && !unmount_root) {
/*
* Special case for "unmounting" root. We just try to remount
* it readonly, and sync() the device.
*/
- if (!(sb=get_super(dev)))
- return -ENOENT;
if (!(sb->s_flags & MS_RDONLY)) {
/*
* Make sure all quotas are turned off on this device we need to mount
@@ -597,35 +604,51 @@ static int do_umount(kdev_t dev,int unmount_root)
}
return 0;
}
- if (!(sb=get_super(dev)) || !(sb->s_covered))
- return -ENOENT;
- if (!sb->s_covered->i_mount)
- printk("VFS: umount(%s): mounted inode has i_mount=NULL\n",
- kdevname(dev));
- while(sb->s_ibasket)
- free_ibasket(sb);
- if(sb->s_mounted->i_dentry)
- d_del(sb->s_mounted->i_dentry, D_NO_CLEAR_INODE);
+
/*
* Before checking if the filesystem is still busy make sure the kernel
* doesn't hold any quotafiles open on that device. If the umount fails
* too bad there are no quotas running anymore. Turn them on again by hand.
*/
quota_off(dev, -1);
- if (!fs_may_umount(dev, sb->s_mounted))
+ if (!fs_may_umount(sb, sb->s_root))
return -EBUSY;
- sb->s_covered->i_mount = NULL;
- iput(sb->s_covered);
- sb->s_covered = NULL;
- iput(sb->s_mounted);
- sb->s_mounted = NULL;
- if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
- sb->s_op->write_super(sb);
- put_super(dev);
+
+ /* clean up dcache .. */
+ d_umount(sb->s_root);
+ sb->s_root = NULL;
+
+ if (sb->s_op) {
+ if (sb->s_op->write_super && sb->s_dirt)
+ sb->s_op->write_super(sb);
+ if (sb->s_op->put_super)
+ sb->s_op->put_super(sb);
+ }
remove_vfsmnt(dev);
return 0;
}
+static int umount_dev(kdev_t dev)
+{
+ int retval;
+ struct inode * inode = get_empty_inode();
+
+ inode->i_rdev = dev;
+ if (MAJOR(dev) >= MAX_BLKDEV)
+ return -ENXIO;
+
+ retval = do_umount(dev,0);
+ if (!retval) {
+ fsync_dev(dev);
+ if (dev != ROOT_DEV) {
+ blkdev_release(inode);
+ put_unnamed_dev(dev);
+ }
+ }
+ iput(inode);
+ return retval;
+}
+
/*
* Now umount can handle mount points as well as block devices.
* This is important for filesystems which use unnamed block devices.
@@ -639,55 +662,36 @@ static int do_umount(kdev_t dev,int unmount_root)
asmlinkage int sys_umount(char * name)
{
- struct inode * inode;
- kdev_t dev;
- struct inode * dummy_inode = NULL;
- int retval = -EPERM;
+ struct dentry * dentry;
+ int retval;
- lock_kernel();
if (!suser())
- goto out;
- retval = namei(NAM_FOLLOW_LINK, name, &inode);
- if (retval) {
- retval = namei(NAM_FOLLOW_TRAILSLASH, name, &inode);
- if (retval)
- goto out;
- }
- if (S_ISBLK(inode->i_mode)) {
- dev = inode->i_rdev;
- retval = -EACCES;
- if (IS_NODEV(inode)) {
- iput(inode);
- goto out;
- }
- } else {
- retval = -EINVAL;
- if (!inode->i_sb || inode != inode->i_sb->s_mounted) {
- iput(inode);
- goto out;
- }
- dev = inode->i_sb->s_dev;
- iput(inode);
- inode = dummy_inode = get_empty_inode();
- inode->i_rdev = dev;
- }
- retval = -ENXIO;
- if (MAJOR(dev) >= MAX_BLKDEV) {
- iput(inode);
- goto out;
- }
- retval = do_umount(dev,0);
- if (!retval) {
- fsync_dev(dev);
- if (dev != ROOT_DEV) {
- blkdev_release (inode);
- put_unnamed_dev(dev);
+ return -EPERM;
+
+ lock_kernel();
+ dentry = namei(name);
+ retval = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+ kdev_t dev = inode->i_rdev;
+
+ retval = 0;
+ if (S_ISBLK(inode->i_mode)) {
+ if (IS_NODEV(inode))
+ retval = -EACCES;
+ } else {
+ struct super_block *sb = inode->i_sb;
+ retval = -EINVAL;
+ if (sb && inode == sb->s_root->d_inode) {
+ dev = sb->s_dev;
+ retval = 0;
+ }
}
+ dput(dentry);
+
+ if (!retval)
+ retval = umount_dev(dev);
}
- iput(inode);
- if (!retval)
- fsync_dev(dev);
-out:
unlock_kernel();
return retval;
}
@@ -715,45 +719,39 @@ out:
int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
{
- struct inode * dir_i = NULL;
+ struct dentry * dir_d = NULL;
struct super_block * sb;
struct vfsmount *vfsmnt;
int error;
- int override = 0;
-
- if(dir_name) {
- char c;
- get_user(c, dir_name);
- override = (c == '!');
- }
if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
return -EACCES;
/*flags |= MS_RDONLY;*/
- if(override)
- dir_name++;
- error = namei(NAM_FOLLOW_LINK, dir_name, &dir_i);
- if (error)
+
+ dir_d = namei(dir_name);
+ error = PTR_ERR(dir_d);
+ if (IS_ERR(dir_d))
return error;
- if (!override && (atomic_read(&dir_i->i_count) != 1 || dir_i->i_mount)) {
- iput(dir_i);
+
+ if (dir_d->d_covers != dir_d) {
+ dput(dir_d);
return -EBUSY;
}
- if (!S_ISDIR(dir_i->i_mode)) {
- iput(dir_i);
+ if (!S_ISDIR(dir_d->d_inode->i_mode)) {
+ dput(dir_d);
return -ENOTDIR;
}
- if (!fs_may_mount(dev) && !override) {
- iput(dir_i);
+ if (!fs_may_mount(dev)) {
+ dput(dir_d);
return -EBUSY;
}
sb = read_super(dev,type,flags,data,0);
if (!sb) {
- iput(dir_i);
+ dput(dir_d);
return -EINVAL;
}
- if (sb->s_covered) {
- iput(dir_i);
+ if (sb->s_root->d_covers != sb->s_root) {
+ dput(dir_d);
return -EBUSY;
}
vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
@@ -761,25 +759,8 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha
vfsmnt->mnt_sb = sb;
vfsmnt->mnt_flags = flags;
}
- {
- struct dentry * old = dir_i->i_dentry;
- struct dentry * new;
- vfs_lock();
- new = d_alloc(old->d_parent, old->d_len, 1);
- if(new) {
- struct qstr copy = { old->d_name, old->d_len };
- d_add(new, sb->s_mounted, &copy, D_DUPLICATE);
- vfs_unlock();
- } else {
- printk("VFS: cannot setup dentry for mount\n");
- iput(dir_i);
- return -ENOMEM;
- }
- vfs_unlock();
- }
- sb->s_covered = dir_i;
- dir_i->i_mount = sb->s_mounted;
- return 0; /* we don't iput(dir_i) - see umount */
+ d_mount(dir_d, sb->s_root);
+ return 0; /* we don't dput(dir) - see umount */
}
@@ -799,7 +780,7 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
/*flags |= MS_RDONLY;*/
/* If we are remounting RDONLY, make sure there are no rw files open */
if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
- if (!fs_may_remount_ro(sb->s_dev))
+ if (!fs_may_remount_ro(sb))
return -EBUSY;
sb->s_flags = (flags & ~MS_RDONLY) | (sb->s_flags & MS_RDONLY);
if (sb->s_op && sb->s_op->remount_fs) {
@@ -817,18 +798,19 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
static int do_remount(const char *dir,int flags,char *data)
{
- struct inode *dir_i;
+ struct dentry *dentry;
int retval;
- retval = namei(NAM_FOLLOW_LINK, dir, &dir_i);
- if (retval)
- return retval;
- if (dir_i != dir_i->i_sb->s_mounted) {
- iput(dir_i);
- return -EINVAL;
+ dentry = namei(dir);
+ retval = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct super_block * sb = dentry->d_inode->i_sb;
+
+ retval = -EINVAL;
+ if (dentry == sb->s_root)
+ retval = do_remount_sb(sb, flags, data);
+ dput(dentry);
}
- retval = do_remount_sb(dir_i->i_sb, flags, data);
- iput(dir_i);
return retval;
}
@@ -879,7 +861,8 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void * data)
{
struct file_system_type * fstype;
- struct inode * inode;
+ struct dentry * dentry = NULL;
+ struct inode * inode = NULL;
struct file_operations * fops;
kdev_t dev;
int retval = -EPERM;
@@ -911,58 +894,54 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
goto out;
t = fstype->name;
fops = NULL;
- if ((fstype->fs_flags & FS_REQUIRES_DEV)) {
- retval = namei(NAM_FOLLOW_LINK, dev_name, &inode);
- if (retval)
+ if (fstype->fs_flags & FS_REQUIRES_DEV) {
+ dentry = namei(dev_name);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
+
+ inode = dentry->d_inode;
retval = -ENOTBLK;
- if (!S_ISBLK(inode->i_mode)) {
- iput(inode);
- goto out;
- }
+ if (!S_ISBLK(inode->i_mode))
+ goto dput_and_out;
+
retval = -EACCES;
- if (IS_NODEV(inode)) {
- iput(inode);
- goto out;
- }
+ if (IS_NODEV(inode))
+ goto dput_and_out;
+
dev = inode->i_rdev;
retval = -ENXIO;
- if (MAJOR(dev) >= MAX_BLKDEV) {
- iput(inode);
- goto out;
- }
+ if (MAJOR(dev) >= MAX_BLKDEV)
+ goto dput_and_out;
+
fops = get_blkfops(MAJOR(dev));
retval = -ENOTBLK;
- if (!fops) {
- iput(inode);
- goto out;
- }
+ if (!fops)
+ goto dput_and_out;
+
if (fops->open) {
struct file dummy; /* allows read-write or read-only flag */
memset(&dummy, 0, sizeof(dummy));
- dummy.f_inode = inode;
+ dummy.f_dentry = dentry;
dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
retval = fops->open(inode, &dummy);
- if (retval) {
- iput(inode);
- goto out;
- }
+ if (retval)
+ goto dput_and_out;
}
} else {
retval = -EMFILE;
if (!(dev = get_unnamed_dev()))
goto out;
- inode = NULL;
}
+
page = 0;
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
flags = new_flags & ~MS_MGC_MSK;
retval = copy_mount_options(data, &page);
if (retval < 0) {
put_unnamed_dev(dev);
- iput(inode);
- goto out;
+ goto dput_and_out;
}
}
retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
@@ -971,7 +950,8 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
fops->release(inode, NULL);
put_unnamed_dev(dev);
}
- iput(inode);
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return retval;
@@ -982,7 +962,7 @@ __initfunc(static void do_mount_root(void))
struct file_system_type * fs_type;
struct super_block * sb;
struct vfsmount *vfsmnt;
- struct inode * inode, * d_inode = NULL;
+ struct inode * d_inode = NULL;
struct file filp;
int retval;
@@ -1001,15 +981,11 @@ __initfunc(static void do_mount_root(void))
sb->s_dev = get_unnamed_dev();
sb->s_flags = root_mountflags & ~MS_RDONLY;
if (nfs_root_mount(sb) >= 0) {
- inode = sb->s_mounted;
- atomic_add(3, &inode->i_count);
- sb->s_covered = inode;
sb->s_rd_only = 0;
sb->s_dirt = 0;
sb->s_type = fs_type;
- current->fs->pwd = inode;
- current->fs->root = inode;
- (void)d_alloc_root(inode);
+ current->fs->root = dget(sb->s_root);
+ current->fs->pwd = dget(sb->s_root);
ROOT_DEV = sb->s_dev;
printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
@@ -1042,7 +1018,7 @@ __initfunc(static void do_mount_root(void))
memset(&filp, 0, sizeof(filp));
d_inode = get_empty_inode();
d_inode->i_rdev = ROOT_DEV;
- filp.f_inode = d_inode;
+ filp.f_dentry = NULL;
if ( root_mountflags & MS_RDONLY)
filp.f_mode = 1; /* read only */
else
@@ -1066,15 +1042,9 @@ __initfunc(static void do_mount_root(void))
continue;
sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
if (sb) {
- inode = sb->s_mounted;
-
- /* NOTE! it is logically used 4 times, not 1 */
- atomic_add(3, &inode->i_count);
- sb->s_covered = inode;
sb->s_flags = root_mountflags;
- current->fs->pwd = inode;
- current->fs->root = inode;
- (void)d_alloc_root(inode);
+ current->fs->root = dget(sb->s_root);
+ current->fs->pwd = dget(sb->s_root);
printk ("VFS: Mounted root (%s filesystem)%s.\n",
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
@@ -1106,8 +1076,7 @@ __initfunc(static int do_change_root(kdev_t new_root_dev,const char *put_old))
{
kdev_t old_root_dev;
struct vfsmount *vfsmnt;
- struct inode *old_root,*old_pwd,*inode;
- unsigned long old_fs;
+ struct dentry *old_root,*old_pwd,*dir_d = NULL;
int error;
old_root = current->fs->root;
@@ -1119,24 +1088,29 @@ __initfunc(static int do_change_root(kdev_t new_root_dev,const char *put_old))
}
ROOT_DEV = new_root_dev;
do_mount_root();
- old_fs = get_fs();
- set_fs(get_ds());
- error = namei(NAM_FOLLOW_LINK, put_old, &inode);
- if (error) inode = NULL;
- set_fs(old_fs);
- if (!error && (atomic_read(&inode->i_count) != 1 || inode->i_mount))
+ dir_d = lookup_dentry(put_old, NULL, 1);
+ if (IS_ERR(dir_d)) {
+ error = PTR_ERR(dir_d);
+ } else if (!dir_d->d_inode) {
+ dput(dir_d);
+ error = -ENOENT;
+ } else {
+ error = 0;
+ }
+ if (!error && dir_d->d_covers != dir_d) {
+ dput(dir_d);
error = -EBUSY;
- if (!error && !S_ISDIR(inode->i_mode))
+ }
+ if (!error && !S_ISDIR(dir_d->d_inode->i_mode)) {
+ dput(dir_d);
error = -ENOTDIR;
- iput(old_root); /* current->fs->root */
- iput(old_pwd); /* current->fs->pwd */
+ }
+ dput(old_root);
+ dput(old_pwd);
if (error) {
int umount_error;
- if (inode) iput(inode);
printk(KERN_NOTICE "Trying to unmount old root ... ");
- old_root->i_mount = old_root;
- /* does this belong into do_mount_root ? */
umount_error = do_umount(old_root_dev,1);
if (umount_error) printk(KERN_ERR "error %d\n",umount_error);
else {
@@ -1145,16 +1119,16 @@ __initfunc(static int do_change_root(kdev_t new_root_dev,const char *put_old))
}
return umount_error ? error : 0;
}
- iput(old_root); /* sb->s_covered */
remove_vfsmnt(old_root_dev);
vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old);
if (!vfsmnt) printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");
else {
- vfsmnt->mnt_sb = old_root->i_sb;
- vfsmnt->mnt_sb->s_covered = inode;
+ vfsmnt->mnt_sb = old_root->d_inode->i_sb;
+ d_mount(dir_d,vfsmnt->mnt_sb->s_root);
vfsmnt->mnt_flags = vfsmnt->mnt_sb->s_flags;
}
- inode->i_mount = old_root;
+ d_umount(old_root);
+ d_mount(dir_d,old_root);
return 0;
}
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index 8b942a5b1..3dd0931cf 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -57,6 +57,7 @@ struct inode_operations sysv_dir_inode_operations = {
sysv_mknod, /* mknod */
sysv_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index da07ef7a8..1a28e4c2a 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -64,6 +64,7 @@ struct inode_operations sysv_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
sysv_bmap, /* bmap */
@@ -194,7 +195,7 @@ long sysv_file_read(struct inode * inode, struct file * filp,
filp->f_reada = 1;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
return read;
}
@@ -255,7 +256,7 @@ static long sysv_file_write(struct inode * inode, struct file * filp,
pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
written += c;
buf += c;
@@ -265,6 +266,6 @@ static long sysv_file_write(struct inode * inode, struct file * filp,
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return written;
}
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 97bc7284f..fa0b3cf95 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -62,9 +62,8 @@ void sysv_free_inode(struct inode * inode)
printk("sysv_free_inode: inode has no device\n");
return;
}
- if (atomic_read(&inode->i_count) != 1) {
- printk("sysv_free_inode: inode has count=%d\n",
- atomic_read(&inode->i_count));
+ if (inode->i_count != 1) {
+ printk("sysv_free_inode: inode has count=%d\n", inode->i_count);
return;
}
if (inode->i_nlink) {
@@ -150,12 +149,12 @@ struct inode * sysv_new_inode(const struct inode * dir)
mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
sb->s_dirt = 1; /* and needs time stamp */
- atomic_set(&inode->i_count, 1);
+ inode->i_count = 1;
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
inode->i_ino = ino;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = NULL;
@@ -166,7 +165,7 @@ struct inode * sysv_new_inode(const struct inode * dir)
inode->i_size = 0; /* ditto */
sysv_write_inode(inode); /* ensure inode not allocated again */
/* FIXME: caller may call this too. */
- inode->i_dirt = 1; /* cleared by sysv_write_inode() */
+ mark_inode_dirty(inode); /* cleared by sysv_write_inode() */
/* That's it. */
(*sb->sv_sb_total_free_inodes)--;
mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified again */
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index f8c6a1b38..b2d7edfbc 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -344,6 +344,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
struct buffer_head *bh;
const char *found;
kdev_t dev = sb->s_dev;
+ struct inode *root_inode;
if (1024 != sizeof (struct xenix_super_block))
panic("Xenix FS: bad super-block size");
@@ -483,9 +484,10 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
/* set up enough so that it can read an inode */
sb->s_dev = dev;
sb->s_op = &sysv_sops;
- sb->s_mounted = iget(sb,SYSV_ROOT_INO);
+ root_inode = iget(sb,SYSV_ROOT_INO);
+ sb->s_root = d_alloc_root(root_inode, NULL);
unlock_super(sb);
- if (!sb->s_mounted) {
+ if (!sb->s_root) {
printk("SysV FS: get root inode failed\n");
sysv_put_super(sb);
return NULL;
@@ -534,7 +536,7 @@ void sysv_put_super(struct super_block *sb)
MOD_DEC_USE_COUNT;
}
-void sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
@@ -547,7 +549,7 @@ void sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
tmp.f_ffree = sysv_count_free_inodes(sb); /* free file nodes in fs */
tmp.f_namelen = SYSV_NAMELEN;
/* Don't know what value to put in tmp.f_fsid */ /* file system id */
- copy_to_user(buf, &tmp, bufsiz);
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
@@ -667,7 +669,7 @@ repeat:
}
*p = tmp;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return result;
}
@@ -900,13 +902,11 @@ static struct buffer_head * sysv_update_inode(struct inode * inode)
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
- inode->i_dirt = 0;
return 0;
}
block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits);
if (!(bh = sv_bread(sb,inode->i_dev,block))) {
printk("unable to read i-node block\n");
- inode->i_dirt = 0;
return 0;
}
raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1);
@@ -937,7 +937,6 @@ static struct buffer_head * sysv_update_inode(struct inode * inode)
else
for (block = 0; block < 10+1+1+1; block++)
write3byte(&raw_inode->i_a.i_addb[3*block],inode->u.sysv_i.i_data[block]);
- inode->i_dirt=0;
mark_buffer_dirty(bh, 1);
return bh;
}
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index d1b67ab5f..b3586b58f 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -175,7 +175,7 @@ static int sysv_add_entry(struct inode * dir,
if (pos > dir->i_size) {
de->inode = 0;
dir->i_size = pos;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
}
if (de->inode) {
if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) {
@@ -184,7 +184,7 @@ static int sysv_add_entry(struct inode * dir,
}
} else {
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
for (i = 0; i < SYSV_NAMELEN ; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
mark_buffer_dirty(bh, 1);
@@ -219,11 +219,11 @@ int sysv_create(struct inode * dir,const char * name, int len, int mode,
}
inode->i_op = &sysv_file_inode_operations;
inode->i_mode = mode;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
error = sysv_add_entry(dir,name,len, &bh ,&de);
if (error) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
iput(dir);
return error;
@@ -276,11 +276,11 @@ int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rde
init_fifo(inode);
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = to_kdev_t(rdev);
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
error = sysv_add_entry(dir, name, len, &bh, &de);
if (error) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
iput(dir);
return error;
@@ -325,7 +325,7 @@ int sysv_mkdir(struct inode * dir, const char * name, int len, int mode)
if (!dir_block) {
iput(dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -ENOSPC;
}
@@ -341,7 +341,7 @@ int sysv_mkdir(struct inode * dir, const char * name, int len, int mode)
inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
error = sysv_add_entry(dir, name, len, &bh, &de);
if (error) {
iput(dir);
@@ -352,7 +352,7 @@ int sysv_mkdir(struct inode * dir, const char * name, int len, int mode)
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
dir->i_nlink++;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
iput(dir);
iput(inode);
brelse(bh);
@@ -454,7 +454,7 @@ int sysv_rmdir(struct inode * dir, const char * name, int len)
retval = -ENOENT;
goto end_rmdir;
}
- if (atomic_read(&inode->i_count) > 1) {
+ if (inode->i_count > 1) {
retval = -EBUSY;
goto end_rmdir;
}
@@ -463,10 +463,10 @@ int sysv_rmdir(struct inode * dir, const char * name, int len)
de->inode = 0;
mark_buffer_dirty(bh, 1);
inode->i_nlink=0;
- inode->i_dirt=1;
+ mark_inode_dirty(inode);
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt=1;
+ mark_inode_dirty(dir);
retval = 0;
end_rmdir:
iput(dir);
@@ -517,10 +517,10 @@ repeat:
de->inode = 0;
mark_buffer_dirty(bh, 1);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
retval = 0;
end_unlink:
brelse(bh);
@@ -550,7 +550,7 @@ int sysv_symlink(struct inode * dir, const char * name, int len, const char * sy
if (!name_block) {
iput(dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -ENOSPC;
}
@@ -563,11 +563,11 @@ int sysv_symlink(struct inode * dir, const char * name, int len, const char * sy
mark_buffer_dirty(name_block, 1);
brelse(name_block);
inode->i_size = i;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
bh = sysv_find_entry(dir,name,len,&de);
if (bh) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
brelse(bh);
iput(dir);
@@ -576,7 +576,7 @@ int sysv_symlink(struct inode * dir, const char * name, int len, const char * sy
i = sysv_add_entry(dir, name, len, &bh, &de);
if (i) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
iput(dir);
return i;
@@ -624,7 +624,7 @@ int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, in
iput(dir);
oldinode->i_nlink++;
oldinode->i_ctime = CURRENT_TIME;
- oldinode->i_dirt = 1;
+ mark_inode_dirty(oldinode);
iput(oldinode);
return 0;
}
@@ -635,7 +635,7 @@ static int subdir(struct inode * new_inode, struct inode * old_inode)
int ino;
int result;
- atomic_inc(&new_inode->i_count);
+ new_inode->i_count++;
result = 0;
for (;;) {
if (new_inode == old_inode) {
@@ -667,8 +667,8 @@ static int subdir(struct inode * new_inode, struct inode * old_inode)
* 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, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len)
+static int do_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;
@@ -687,21 +687,21 @@ try_again:
start_up:
old_inode = new_inode = NULL;
old_bh = new_bh = dir_bh = NULL;
- old_bh = sysv_find_entry(old_dir,old_name,old_len,&old_de);
+ old_bh = sysv_find_entry(old_dir,old_dentry->d_name.name,
+ old_dentry->d_name.len,&old_de);
retval = -ENOENT;
if (!old_bh)
goto end_rename;
- old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
- if (!old_inode)
- goto end_rename;
+ old_inode = old_dentry->d_inode;/* don't cross mnt-points */
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
current->fsuid != old_dir->i_uid && !fsuser())
goto end_rename;
- new_bh = sysv_find_entry(new_dir,new_name,new_len,&new_de);
+ new_inode = new_dentry->d_inode;
+ new_bh = sysv_find_entry(new_dir,new_dentry->d_name.name,
+ new_dentry->d_name.len,&new_de);
if (new_bh) {
- new_inode = __iget(new_dir->i_sb, new_de->inode, 0);
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
@@ -722,7 +722,7 @@ start_up:
if (!empty_dir(new_inode))
goto end_rename;
retval = -EBUSY;
- if (atomic_read(&new_inode->i_count) > 1)
+ if (new_inode->i_count > 1)
goto end_rename;
}
retval = -EPERM;
@@ -748,7 +748,8 @@ start_up:
goto end_rename;
}
if (!new_bh) {
- retval = sysv_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
+ retval = sysv_add_entry(new_dir,new_dentry->d_name.name,
+ new_dentry->d_name.len,&new_bh,&new_de);
if (retval)
goto end_rename;
}
@@ -763,13 +764,13 @@ start_up:
old_de->inode = 0;
new_de->inode = old_inode->i_ino;
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
- old_dir->i_dirt = 1;
+ mark_inode_dirty(old_dir);
new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
- new_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
}
mark_buffer_dirty(old_bh, 1);
mark_buffer_dirty(new_bh, 1);
@@ -777,13 +778,13 @@ start_up:
PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
mark_buffer_dirty(dir_bh, 1);
old_dir->i_nlink--;
- old_dir->i_dirt = 1;
+ mark_inode_dirty(old_dir);
if (new_inode) {
new_inode->i_nlink--;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
} else {
new_dir->i_nlink++;
- new_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
}
}
retval = 0;
@@ -807,8 +808,8 @@ end_rename:
* 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, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len)
+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;
@@ -817,8 +818,8 @@ int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
while (lock)
sleep_on(&wait);
lock = 1;
- result = do_sysv_rename(old_dir, old_name, old_len,
- new_dir, new_name, new_len);
+ result = do_sysv_rename(old_dir, old_dentry,
+ new_dir, new_dentry);
lock = 0;
wake_up(&wait);
return result;
diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c
index 4e8a5e349..d76c3fa66 100644
--- a/fs/sysv/symlink.c
+++ b/fs/sysv/symlink.c
@@ -21,6 +21,7 @@
#include <asm/uaccess.h>
static int sysv_readlink(struct inode *, char *, int);
+static struct dentry *sysv_follow_link(struct inode *, struct dentry *);
/*
* symlinks can't do much...
@@ -37,6 +38,7 @@ struct inode_operations sysv_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
sysv_readlink, /* readlink */
+ sysv_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -44,6 +46,21 @@ struct inode_operations sysv_symlink_inode_operations = {
NULL /* permission */
};
+static struct dentry *sysv_follow_link(struct inode * inode, struct dentry * base)
+{
+ struct buffer_head * bh;
+
+ bh = sysv_file_bread(inode, 0, 0);
+ if (!bh) {
+ dput(base);
+ return ERR_PTR(-EIO);
+ }
+ UPDATE_ATIME(inode);
+ base = lookup_dentry(bh->b_data, base, 1);
+ brelse(bh);
+ return base;
+}
+
static int sysv_readlink(struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh;
@@ -54,7 +71,6 @@ static int sysv_readlink(struct inode * inode, char * buffer, int buflen)
if (buflen > inode->i_sb->sv_block_size_1)
buflen = inode->i_sb->sv_block_size_1;
bh = sysv_file_bread(inode, 0, 0);
- iput(inode);
if (!bh)
return 0;
bh_data = bh->b_data;
diff --git a/fs/sysv/truncate.c b/fs/sysv/truncate.c
index 0eeb10d30..433c39cae 100644
--- a/fs/sysv/truncate.c
+++ b/fs/sysv/truncate.c
@@ -64,7 +64,7 @@ repeat:
continue;
}
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
brelse(bh);
sysv_free_block(sb,block);
}
@@ -257,12 +257,14 @@ done:
static int trunc_all(struct inode * inode)
{
struct super_block * sb;
+ char * res;
sb = inode->i_sb;
+ res = (char *)test_bit(I_DIRTY,&inode->i_state);
return trunc_direct(inode)
- | trunc_indirect(inode,sb->sv_ind0_size,&inode->u.sysv_i.i_data[10],0,&inode->i_dirt)
- | trunc_dindirect(inode,sb->sv_ind1_size,&inode->u.sysv_i.i_data[11],0,&inode->i_dirt)
- | trunc_tindirect(inode,sb->sv_ind2_size,&inode->u.sysv_i.i_data[12],0,&inode->i_dirt);
+ | trunc_indirect(inode,sb->sv_ind0_size,&inode->u.sysv_i.i_data[10],0,res)
+ | trunc_dindirect(inode,sb->sv_ind1_size,&inode->u.sysv_i.i_data[11],0,res)
+ | trunc_tindirect(inode,sb->sv_ind2_size,&inode->u.sysv_i.i_data[12],0,res);
}
@@ -285,5 +287,5 @@ void sysv_truncate(struct inode * inode)
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
diff --git a/fs/ufs/ufs_file.c b/fs/ufs/ufs_file.c
index 74ae1a470..ef7858c8f 100644
--- a/fs/ufs/ufs_file.c
+++ b/fs/ufs/ufs_file.c
@@ -6,7 +6,7 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_file.c,v 1.8 1997/06/05 01:29:09 davem Exp $
+ * $Id: ufs_file.c,v 1.2 1997/06/17 13:27:28 ralf Exp $
*
*/
@@ -41,6 +41,7 @@ struct inode_operations ufs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
ufs_bmap, /* bmap */
diff --git a/fs/ufs/ufs_inode.c b/fs/ufs/ufs_inode.c
index f0fdd5d5f..d8c8c6896 100644
--- a/fs/ufs/ufs_inode.c
+++ b/fs/ufs/ufs_inode.c
@@ -6,7 +6,7 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_inode.c,v 1.8 1997/06/04 08:28:28 davem Exp $
+ * $Id: ufs_inode.c,v 1.2 1997/06/17 13:27:29 ralf Exp $
*
*/
@@ -19,8 +19,7 @@ void ufs_print_inode(struct inode * inode)
printk("ino %lu mode 0%6.6o lk %d uid %d gid %d"
" sz %lu blks %lu cnt %u\n",
inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid,
- inode->i_gid, inode->i_size, inode->i_blocks,
- atomic_read(&inode->i_count));
+ inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count);
printk(" db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x"
" 0x%x 0x%x 0x%x 0x%x>\n",
inode->u.ufs_i.i_data[0], inode->u.ufs_i.i_data[1],
diff --git a/fs/ufs/ufs_namei.c b/fs/ufs/ufs_namei.c
index 03ea2dde1..64ea3a866 100644
--- a/fs/ufs/ufs_namei.c
+++ b/fs/ufs/ufs_namei.c
@@ -6,7 +6,7 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_namei.c,v 1.7 1996/06/01 14:56:49 ecd Exp $
+ * $Id: ufs_namei.c,v 1.1.1.1 1997/06/01 03:16:19 ralf Exp $
*
*/
@@ -35,12 +35,14 @@ static int ufs_match (int len, const char * const name, struct ufs_direct * d)
}
/* XXX - this is a mess, especially for endianity */
-int ufs_lookup (struct inode * dir, const char * name, int len,
+int ufs_lookup (struct inode * dir, struct qstr *qname,
struct inode ** result)
{
unsigned long int lfragno, fragno;
struct buffer_head * bh;
struct ufs_direct * d;
+ const char *name = qname->name;
+ int len = qname->len;
if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG)
printk("Passed name: %s\nPassed length: %d\n", name, len);
diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c
index 342722237..f08292a23 100644
--- a/fs/ufs/ufs_super.c
+++ b/fs/ufs/ufs_super.c
@@ -8,7 +8,7 @@
*
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*
- * $Id: ufs_super.c,v 1.24 1997/06/04 08:28:29 davem Exp $
+ * $Id: ufs_super.c,v 1.2 1997/06/17 13:27:29 ralf Exp $
*
*/
@@ -254,7 +254,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
sb->u.ufs_sb.s_lmask = ~((ufs_swab32(usb->fs_fmask) - ufs_swab32(usb->fs_bmask))
>> ufs_swab32(usb->fs_fshift));
sb->u.ufs_sb.s_fsfrag = ufs_swab32(usb->fs_frag); /* XXX - rename this later */
- sb->s_mounted = iget(sb, UFS_ROOTINO);
+ sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
#ifdef DEBUG_UFS_SUPER
printk("ufs_read_super: inopb %u\n", sb->u.ufs_sb.s_inopb);
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 161bc791e..b3263b42d 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -877,7 +877,7 @@ static int vfat_find(struct inode *dir,const char *name,int len,
PRINTK(("vfat_find: create file 4\n"));
dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
PRINTK(("vfat_find: create file 5\n"));
@@ -1010,7 +1010,7 @@ static int vfat_create_entry(struct inode *dir,const char *name,int len,
return -EIO;
(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
CURRENT_TIME;
- (*result)->i_dirt = 1;
+ mark_inode_dirty(*result);
(*result)->i_version = ++event;
dir->i_version = event;
@@ -1046,7 +1046,7 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
* XXX all times should be set by caller upon successful completion.
*/
dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
memcpy(de->name,name,MSDOS_NAME);
memset(de->unused, 0, sizeof(de->unused));
de->lcase = 0;
@@ -1062,7 +1062,7 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
vfat_read_inode(dot);
if (!dot) return -EIO;
dot->i_mtime = dot->i_atime = CURRENT_TIME;
- dot->i_dirt = 1;
+ mark_inode_dirty(dot);
if (isdot) {
dot->i_size = dir->i_size;
MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
@@ -1125,7 +1125,7 @@ static int vfat_empty(struct inode *dir)
struct buffer_head *bh;
struct msdos_dir_entry *de;
- if (atomic_read(&dir->i_count) > 1)
+ if (dir->i_count > 1)
return -EBUSY;
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
@@ -1173,7 +1173,8 @@ static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh,
inode->i_mtime = dir->i_mtime = CURRENT_TIME;
inode->i_atime = dir->i_atime = CURRENT_TIME;
dir->i_nlink--;
- inode->i_dirt = dir->i_dirt = 1;
+ mark_inode_dirty(dir);
+ mark_inode_dirty(inode);
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
iput(inode);
@@ -1196,7 +1197,8 @@ static int vfat_unlink_free_ino(struct inode *dir,struct buffer_head *bh,
inode->i_atime = dir->i_atime = CURRENT_TIME;
dir->i_version = ++event;
MSDOS_I(inode)->i_busy = 1;
- inode->i_dirt = dir->i_dirt = 1;
+ mark_inode_dirty(dir);
+ mark_inode_dirty(inode);
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
@@ -1478,7 +1480,7 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
MSDOS_I(new_inode)->i_oldlink = old_inode;
fat_cache_inval_inode(old_inode);
PRINTK(("vfat_rename 15: old_slots=%d\n",old_slots));
- old_inode->i_dirt = 1;
+ mark_inode_dirty(old_inode);
old_dir->i_version = ++event;
/* remove the old entry */
@@ -1511,7 +1513,7 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
}
dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
MSDOS_I(new_dir)->i_start;
- dotdot_inode->i_dirt = 1;
+ mark_inode_dirty(dotdot_inode);
fat_mark_buffer_dirty(sb, dotdot_bh, 1);
old_dir->i_nlink--;
new_dir->i_nlink++;