- Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
- =====================================================================
+ Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
+ =====================================================================
This Kernel feature allows to invoke almost (for restrictions see below) every
-program by simply typing it's name in the shell.
+program by simply typing its name in the shell.
This includes for example compiled Java(TM), Python or Emacs programs.
-To achieve this you must tell binfmt_misc which interpreter has to be invoked with
-which binary. Binfmt_misc recognises the binary-type by matching some bytes at the
-beginning of the file with a magic byte sequence (masking out specified bits) you
-have supplied. Binfmt_misc can also recognise a filename extension (aka .com) and
-optionally strip it off.
+To achieve this you must tell binfmt_misc which interpreter has to be invoked
+with which binary. Binfmt_misc recognises the binary-type by matching some bytes
+at the beginning of the file with a magic byte sequence (masking out specified
+bits) you have supplied. Binfmt_misc can also recognise a filename extension
+(aka .com) and optionally strip it off.
To actually register a new binary type, you have to set up a string looking like
-:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon your
-needs) and echo it to /proc/sys/fs/binfmt_misc/register.
+:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon
+your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
Here is what the fields mean:
- 'name' is an identifier string. A new /proc file will be created with this
- this name below /proc/sys/fs/binfmt_misc
+ name below /proc/sys/fs/binfmt_misc
- 'type' is the type of recognition. Give 'M' for magic and 'E' for extension.
- Give the corresponding lowercase letter to let binfmt_misc strip of the
+ Give the corresponding lowercase letter to let binfmt_misc strip off the
filename extension.
- - 'offset' is the offset of the magic/mask in the file counted in bytes. This
+ - 'offset' is the offset of the magic/mask in the file, counted in bytes. This
defaults to 0 if you omit it (i.e. you write ':name:type::magic...')
- 'magic' is the byte sequence binfmt_misc is matching for. The magic string
may contain hex-encoded characters like \x0a or \xA4. In a shell environment
If you chose filename extension matching, this is the extension to be
recognised (the \x0a specials are not allowed). Extension matching is case
sensitive!
- - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some bits
- from matching by supplying a string like magic and as long as magic. The
- mask is anded with the byte sequence of the file.
+ - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some
+ bits from matching by supplying a string like magic and as long as magic.
+ The mask is anded with the byte sequence of the file.
- 'interpreter' is the program that should be invoked with the binary as first
argument (specify the full path)
There are some restrictions:
- the whole register string may not exceed 255 characters
- - the magic must resist in the first 128 bytes of the file, i.e. offset+size(magic)
- has to be less than 128
+ - the magic must resist in the first 128 bytes of the file, i.e.
+ offset+size(magic) has to be less than 128
- the interpreter string may not exceed 127 characters
-You may want to add the binary formats in one of your /etc/rc scripts during boot-up.
-Read the manual of your init program to figure out how to do this right.
+You may want to add the binary formats in one of your /etc/rc scripts during
+boot-up. Read the manual of your init program to figure out how to do this
+right.
A few examples (assumed you are in /proc/sys/fs/binfmt_misc):
-- enable Java(TM)-support (like binfmt_java):
- echo ":Java:M::\xca\xfe\xba\xbe::/usr/local/bin/java:" > register
- echo :Applet:M::\<\!--applet::/usr/local/bin/appletviewer: > register
-
- enable support for em86 (like binfmt_em86, for Alpha AXP only):
echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
- enable support for DOS/Windows executables (using mzloader and dosemu/wine):
echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register
- echo ":DOS:E::com::/usr/sbin/mzloader:" > register
- echo ":DOS2:E::exe::/usr/sbin/mzloader:" > register
+ echo ":DOScom:E::com::/usr/sbin/mzloader:" > register
+ echo ":DOSexe:E::exe::/usr/sbin/mzloader:" > register
+
You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable)
or 1 (to enable) to /proc/sys/fs/binfmt_misc/status or /proc/.../the_name.
or /proc/sys/fs/binfmt_misc/status.
+Emulating binfmt_java:
+======================
+
+To emulate binfmt_java the following register-strings are necessary
+(the first two for byte-compiled Java binaries, the third for applets
+contained in a html-file). Register exactly in this order!
+ ":Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/java:"
+ ":JavaC:e::class::/usr/local/java/bin/java:"
+ ":Applet:E::html::/usr/local/java/bin/appletviewer:"
+
+To add a Java-executable to your path you can either make a symbolic
+link to the .class file elsewhere in your path (cut the .class-extension
+in the destination name for convenience) or add the directory of your
+.class files to your PATH environment. In both cases, ensure that the
+.class files are in your CLASSPATH environment!
+
+This is sort of ugly - Javas filename handling is just broken.
+
+
HINTS:
======
/*
* No entries except for "." and "..", both of which are handled by the VFS layer
*/
-static int autofs_dir_lookup(struct inode *dir, struct qstr *str, struct inode **result)
+static int autofs_dir_lookup(struct inode *dir, struct dentry * dentry)
{
- return -ENOENT; /* No other entries */
+ d_add(dentry, NULL);
+ return 0;
}
static struct file_operations autofs_dir_operations = {
#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;
+}
+
+static void autofs_delete_inode(struct inode *inode)
+{
inode->i_size = 0;
}
static struct super_operations autofs_sops = {
autofs_read_inode,
- NULL,
autofs_write_inode,
autofs_put_inode,
+ autofs_delete_inode,
+ NULL, /* notify_change */
autofs_put_super,
- NULL,
+ NULL, /* write_super */
autofs_statfs,
NULL
};
#include "autofs_i.h"
static int autofs_root_readdir(struct inode *,struct file *,void *,filldir_t);
-static int autofs_root_lookup(struct inode *,struct qstr *,struct inode **);
+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 *);
return 0;
}
-static int autofs_root_lookup(struct inode *dir, struct qstr *str, 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;
+
+ while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
+ int status = autofs_wait(sbi, &dentry->d_name);
+
+ /* Turn this into a real negative dentry? */
+ if (status == -ENOENT) {
+ dentry->d_flags = 0;
+ return 0;
+ }
+ if (status)
+ return status;
+ }
+
+ if (!dentry->d_inode) {
+ inode = iget(sb, ent->ino);
+ if (!inode)
+ return -EACCES;
+
+ dentry->d_inode = inode;
+ }
+
+ 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;
+
+ sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
+
+ /* Incomplete dentry? */
+ if (dentry->d_flags) {
+ if (autofs_oz_mode(sbi))
+ return dentry;
+
+ try_to_fill_dentry(dentry, dir->i_sb, sbi);
+ return dentry;
+ }
+
+ /* Negative dentry.. Should we time these out? */
+ if (!dentry->d_inode)
+ return dentry;
+
+ /* We should update the usage stuff here.. */
+ return dentry;
+}
+
+static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
+{
+ struct autofs_sb_info *sbi;
struct inode *res;
- int status, oz_mode;
+ int oz_mode;
DPRINTK(("autofs_root_lookup: name = "));
- autofs_say(str->name,str->len);
+ autofs_say(dentry->d_name.name,dentry->d_name.len);
- *result = NULL;
- if (!dir)
- return -ENOENT;
if (!S_ISDIR(dir->i_mode))
return -ENOTDIR;
- *result = res = NULL;
+ 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));
- do {
- while ( !(ent = autofs_hash_lookup(&sbi->dirhash,str)) ) {
- DPRINTK(("lookup failed, pid = %u, pgrp = %u\n", current->pid, current->pgrp));
-
- if ( oz_mode )
- return -ENOENT;
- up(&dir->i_sem);
- status = autofs_wait(sbi,str);
- down(&dir->i_sem);
- DPRINTK(("autofs_wait returned %d\n", status));
- if ( status )
- return status;
- }
-
- DPRINTK(("lookup successful, inode = %08x\n", (unsigned int)ent->ino));
-
- if (!(res = iget(dir->i_sb,ent->ino))) {
- printk("autofs: iget returned null!\n");
- return -EACCES;
- }
-
- if ( !oz_mode && S_ISDIR(res->i_mode) && i_dentry(res)->d_covers == i_dentry(res)) {
- /* 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;
- up(&dir->i_sem);
- status = autofs_wait(sbi,str);
- down(&dir->i_sem);
- if ( status )
- return status;
- }
- } while(!res);
- autofs_update_usage(&sbi->dirhash,ent);
-
- *result = res;
+ /*
+ * 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;
}
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) )
return -EPERM;
#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);
char *iname_addr = iname, *p;
int retval, fmt_flags = 0;
+ MOD_INC_USE_COUNT;
if (!enabled) {
retval = -ENOEXEC;
goto _ret;
if (retval >= 0)
retval = search_binary_handler(bprm, regs);
_ret:
+ MOD_DEC_USE_COUNT;
return retval;
}
struct binfmt_entry *e;
int memsize, cnt = count - 1, err = 0;
+ MOD_INC_USE_COUNT;
/* some sanity checks */
- if ((count < 11) || (count > 256))
- return -EINVAL;
+ if ((count < 11) || (count > 256)) {
+ err = -EINVAL;
+ goto _err;
+ }
memsize = sizeof(struct binfmt_entry) + count;
- if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
- return -ENOMEM;
+ if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
+ err = -ENOMEM;
+ goto _err;
+ }
sp = buffer + 1;
del = buffer[0];
!(e->proc_name) || !(e->interpreter) ||
entry_proc_setup(e)) {
kfree(e);
- return -EINVAL;
+ err = -EINVAL;
+ goto _err;
}
write_lock(&entries_lock);
entries = e;
write_unlock(&entries_lock);
- return count;
+ err = count;
+_err:
+ MOD_DEC_USE_COUNT;
+ return err;
}
/*
char *dp;
int elen, i;
+ MOD_INC_USE_COUNT;
#ifndef VERBOSE_STATUS
if (data) {
read_lock(&entries_lock);
*eof = (elen <= count) ? 1 : 0;
*start = page + off;
+ MOD_DEC_USE_COUNT;
return elen;
}
struct binfmt_entry *e;
int res = count;
+ MOD_INC_USE_COUNT;
if (((buffer[0] == '1') || (buffer[0] == '0')) &&
((count == 1) || ((count == 2) && (buffer[1] == '\n')))) {
if (data) {
} else {
res = -EINVAL;
}
+ MOD_DEC_USE_COUNT;
return res;
}
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) {
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;
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;
return NULL;
}
-int ext2_lookup(struct inode * dir, struct qstr *name, 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))
- return -ENOTDIR;
-
- if (name->len > EXT2_NAME_LEN)
+ if (dentry->d_name.len > EXT2_NAME_LEN)
return -ENAMETOOLONG;
- ino = dir->i_version;
- if (!(bh = ext2_find_entry (dir, name->name, name->len, &de)))
- return -ENOENT;
-
- ino = le32_to_cpu(de->inode);
- brelse (bh);
- if (!(*result = iget (dir->i_sb, ino)))
- return -EACCES;
+ 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;
+ }
+ d_add(dentry, inode);
return 0;
}
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.
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
- atomic_inc(&inode->i_count);
+ 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, &(struct qstr) { "..", 2, 0 }, &new_inode))
- break;
- if (new_inode->i_ino == ino)
- break;
+ result = 1;
+ break;
}
- iput (new_inode);
return result;
}
((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.
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;
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)
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,
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) {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
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);
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;
}
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);
}
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){
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;
}
-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;
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;
}
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",
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");
}
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));
#ifdef DEBUG
printk("size is %d now (%x)\n",inode->i_size,inode);
#endif
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
return 0;
}
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;
return -EACCES;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
- vma->vm_inode = inode;
+ vma->vm_dentry = dget(file->f_dentry);
atomic_inc(&inode->i_count);
vma->vm_ops = &fat_file_mmap;
return 0;
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;
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);
}
if (IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->drop(inode);
- spin_lock(&inode_lock);
inode->i_state = 0;
- list_del(&inode->i_hash);
- list_del(&inode->i_list);
- list_add(&inode->i_list, &inode_unused);
- spin_unlock(&inode_lock);
}
#define CAN_UNUSE(inode) \
- ((atomic_read(&(inode)->i_count) == 0) && \
+ (((inode)->i_count == 0) && \
((inode)->i_nrpages == 0) && \
- (!test_bit(I_LOCK, &(inode)->i_state)))
+ (!(inode)->i_state))
static void invalidate_list(struct list_head *head, kdev_t dev)
{
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);
}
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);
continue;
if (inode->i_ino != ino)
continue;
- atomic_inc(&inode->i_count);
+ inode->i_count++;
break;
}
return inode;
void clean_inode(struct inode *inode)
{
memset(&inode->u, 0, sizeof(inode->u));
- inode->i_pipe = 0;
inode->i_sock = 0;
inode->i_op = NULL;
- inode->i_nlink = 1;
+ inode->i_nlink = 0;
inode->i_writecount = 0;
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
sema_init(&inode->i_sem, 1);
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:
- INIT_LIST_HEAD(&inode->i_hash);
inode->i_sb = NULL;
inode->i_ino = ++last_ino;
- atomic_set(&inode->i_count, 1);
+ inode->i_count = 1;
list_add(&inode->i_list, &inode_in_use);
inode->i_state = 0;
spin_unlock(&inode_lock);
return inode;
}
-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;
- atomic_set(&inode->i_count, 1);
- 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_pipe = 1;
- 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;
-}
-
/*
* This is called with the inode lock held.. Be careful.
*/
inode->i_dev = sb->s_dev;
inode->i_ino = ino;
inode->i_flags = sb->s_flags;
- atomic_set(&inode->i_count, 1);
+ inode->i_count = 1;
inode->i_state = 1 << I_LOCK;
spin_unlock(&inode_lock);
clean_inode(inode);
void iput(struct inode *inode)
{
if (inode) {
- if (inode->i_pipe)
- wake_up_interruptible(&PIPE_WAIT(*inode));
+ struct super_operations *op = NULL;
- /*
- * Last user dropping the inode?
- */
- if (atomic_read(&inode->i_count) == 1) {
- void (*put)(struct inode *);
+ if (inode->i_sb && inode->i_sb->s_op)
+ op = inode->i_sb->s_op;
+ if (op && op->put_inode)
+ op->put_inode(inode);
- if (inode->i_pipe) {
- free_page((unsigned long)PIPE_BASE(*inode));
- PIPE_BASE(*inode)= NULL;
+ spin_lock(&inode_lock);
+ if (!--inode->i_count) {
+ if (!inode->i_nlink) {
+ list_del(&inode->i_hash);
+ INIT_LIST_HEAD(&inode->i_hash);
+ if (op && op->delete_inode) {
+ void (*delete)(struct inode *) = op->delete_inode;
+ spin_unlock(&inode_lock);
+ delete(inode);
+ spin_lock(&inode_lock);
+ }
}
-
- if (inode->i_sb && inode->i_sb->s_op) {
- put = inode->i_sb->s_op->put_inode;
- if (put)
- put(inode);
+ if (list_empty(&inode->i_hash)) {
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, &inode_unused);
}
}
- atomic_dec(&inode->i_count);
+ spin_unlock(&inode_lock);
}
}
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;
/* 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;
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,
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 */
/* 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;
* 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;
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
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 */
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;
}
}
return NULL;
}
-int isofs_lookup(struct inode * dir, struct qstr *name,
- 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, name->len);
+ printk("lookup: %x %d\n",dir->i_ino, dentry->d_name.len);
#endif
if (!dir)
return -ENOENT;
* then first convert this name to lower case.
*/
if (dir->i_sb->u.isofs_sb.s_name_check == 'r' &&
- (lcname = kmalloc(name->len, GFP_KERNEL)) != NULL) {
+ (lcname = kmalloc(dentry->d_name.len, GFP_KERNEL)) != NULL) {
int i;
char c;
- for (i=0; i<name->len; i++) {
- c = name->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, name->len,
- &ino, &ino_back);
+ bh = isofs_find_entry(dir, lcname, dentry->d_name.len, &ino);
kfree(lcname);
} else
- bh = isofs_find_entry(dir, name->name,
- name->len, &ino, &ino_back);
+ bh = isofs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &ino);
- if (!bh)
- return -ENOENT;
- brelse(bh);
+ inode = NULL;
+ if (bh) {
+ brelse(bh);
- 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 && !inode->i_pipe && inode->i_sb == dir->i_sb)
- inode->u.isofs_i.i_backlink = ino_back;
-
- *result = inode;
-
+ inode = iget(dir->i_sb,ino);
+ if (!inode)
+ return -EACCES;
+ }
+ d_add(dentry, inode);
return 0;
}
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;
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;
}
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;
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;
}
/*
}
*p = tmp;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return result;
}
}
*p = tmp;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return result;
}
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) +
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;
}
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) +
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;
}
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)) {
}
} 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;
return -ENOSPC;
inode->i_op = &minix_file_inode_operations;
inode->i_mode = mode;
- inode->i_dirt = 1;
+ 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);
return error;
}
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 = 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);
return error;
}
dir_block = minix_bread(inode,0,1);
if (!dir_block) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -ENOSPC;
}
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 = minix_add_entry(dir, dentry->d_name.name,
dentry->d_name.len, &bh, &de);
if (error) {
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
dir->i_nlink++;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
brelse(bh);
d_instantiate(dentry, inode);
return 0;
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:
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:
name_block = minix_bread(inode,0,1);
if (!name_block) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -ENOSPC;
}
mark_buffer_dirty(name_block, 1);
brelse(name_block);
inode->i_size = i;
- inode->i_dirt = 1;
+ 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);
return -EEXIST;
dentry->d_name.len, &bh, &de);
if (i) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return i;
}
brelse(bh);
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
d_instantiate(dentry, inode);
return 0;
}
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);
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 */
#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...
NULL, /* mknod */
NULL, /* rename */
minix_readlink, /* readlink */
+ minix_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
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;
if (buflen > 1023)
buflen = 1023;
bh = minix_bread(inode, 0, 0);
- iput(inode);
if (!bh)
return 0;
i = 0;
continue;
}
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
if (bh) {
mark_buffer_clean(bh);
brelse(bh);
else {
tmp = *p;
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
/*
continue;
}
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
if (bh) {
mark_buffer_clean(bh);
brelse(bh);
else {
tmp = *p;
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
else {
tmp = *p;
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
brelse(tind_bh);
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
/*
* 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;
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;
}
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;
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;
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);
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:
}
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);
}
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);
}
}
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);
}
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++;
NULL, /* mknod */
msdos_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
*/
static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
{
+ struct dentry * result;
struct inode *dir = parent->d_inode;
- struct dentry *result;
- struct inode *inode;
- int error = -ENOTDIR;
-
- down(&dir->i_sem);
-
- error = -ENOTDIR;
- if (dir->i_op && dir->i_op->lookup)
- error = dir->i_op->lookup(dir, name, &inode);
- result = ERR_PTR(error);
-
- if (!error || error == -ENOENT) {
- struct dentry *new;
-
- if (error)
- inode = NULL;
-
- new = d_alloc(parent, name);
- /*
- * Ok, now we can't sleep any more. Double-check that
- * nobody else added this in the meantime..
- */
+ result = ERR_PTR(-ENOTDIR);
+ if (dir->i_op && dir->i_op->lookup) {
+ down(&dir->i_sem);
result = d_lookup(parent, name);
- if (result) {
- d_free(new);
- iput(inode);
- } else {
- d_add(new, inode);
- result = new;
+ 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);
}
up(&dir->i_sem);
return result;
struct dentry * dentry = d_lookup(parent, name);
if (dentry) {
- if (dentry->d_revalidate)
+ if (dentry->d_revalidate) {
+ /* spin_unlock(&dentry_lock); */
dentry = dentry->d_revalidate(dentry);
+ /* spin_lock(&dentry_lock); */
+ }
/*
* The parent d_count _should_ be at least 2: one for the
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 *, struct qstr *, struct inode **);
+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_lookup(struct inode *dir, struct qstr * __name,
- struct inode **result)
+static int nfs_lookup(struct inode *dir, struct dentry * dentry)
{
+ struct inode *inode;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
- int len = __name->len;
- 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->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");
return -ENOENT;
if (len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- memcpy(name,__name->name,len);
- name[len] = '\0';
+ error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &fhandle, &fattr);
- error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
- name, &fhandle, &fattr);
- if (error)
+ inode = NULL;
+ if (!error) {
+ error = -ENOENT;
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
+ return -EACCES;
+ } else if (error != -ENOENT)
return error;
- if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr)))
- return -EACCES;
-
+ d_add(dentry, inode);
return 0;
}
if (error)
return error;
- atomic_inc(&inode->i_count);
+ inode->i_count++;
d_instantiate(dentry, inode);
return 0;
}
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");
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) {
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 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 */
nfs_put_inode(struct inode * inode)
{
dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+}
- 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
}
dprintk("NFS: fhget(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino,
- atomic_read(&inode->i_count));
+ inode->i_count);
return inode;
}
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);
nfs_readpage_result, req);
if (result >= 0) {
- atomic_inc(&inode->i_count);
atomic_inc(&page->count);
return 0;
}
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);
status = req->wb_task.tk_status;
remove_write_request(&nfs_failed_requests, req);
- iput(req->wb_inode);
kfree(req);
return status;
}
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)) {
kfree(req);
free_page(page_address(page));
- iput(inode);
nr_write_requests--;
}
tmp = current->fs->root;
current->fs->root = dentry;
dentry = tmp;
+ error = 0;
dput_and_out:
dput(dentry);
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_READERS(*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)
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)
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;
+ inode->i_count = 1;
+ 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 */
# 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
+++ /dev/null
-/*
- * $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:
- return error;
-}
#include <linux/stat.h>
static int proc_readfd(struct inode *, struct file *, void *, filldir_t);
-static int proc_lookupfd(struct inode *,struct qstr *,struct inode **);
+static int proc_lookupfd(struct inode *, struct dentry *);
static struct file_operations proc_fd_operations = {
NULL, /* lseek - default */
NULL /* permission */
};
-static int proc_lookupfd(struct inode * dir, struct qstr *str, 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;
return -ENOENT;
fd = 0;
- len = str->len;
- name = str->name;
+ len = dentry->d_name.len;
+ name = dentry->d_name.name;
while (len-- > 0) {
c = *name - '0';
name++;
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;
}
&& 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;
}
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,
#define FIRST_PROCESS_ENTRY 256
static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
-static int proc_root_lookup(struct inode *,struct qstr *,struct inode **);
+static int proc_root_lookup(struct inode *,struct dentry *);
static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
proc_openprom_deflookup)
return proc_openprom_inode_operations.lookup
(dir, str, result);
- iput(dir);
return -ENOENT;
}
#endif
proc_tty_init();
}
-
-int proc_lookup(struct inode * dir, struct qstr * str, 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;
- *result = NULL;
if (!dir || !S_ISDIR(dir->i_mode))
return -ENOTDIR;
de = (struct proc_dir_entry *) dir->u.generic_ip;
- if (!de)
- return -EINVAL;
-
- *result = NULL;
- for (de = de->subdir; de ; de = de->next) {
- if (!de || !de->low_ino)
- continue;
- if (de->namelen != str->len)
- continue;
- if (!memcmp(str->name, de->name, str->len)) {
- int ino = de->low_ino | (dir->i_ino & ~(0xffff));
- if (!(*result = proc_get_inode(dir->i_sb, ino, de)))
- return -EINVAL;
- 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;
+ }
}
}
- return -ENOENT;
+ if (!inode)
+ return -ENOENT;
+
+ d_add(dentry, inode);
+ return 0;
}
-static int proc_root_lookup(struct inode * dir,struct qstr *str, 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;
const char *name;
+ struct inode *inode;
int len;
- atomic_inc(&dir->i_count);
-
if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
dir->i_nlink = proc_root.nlink;
read_unlock(&tasklist_lock);
}
- retval = proc_lookup(dir, str, result);
- if (retval != -ENOENT)
- return retval;
+ if (!proc_lookup(dir, dentry))
+ return 0;
pid = 0;
- name = str->name;
- len = str->len;
+ name = dentry->d_name.name;
+ len = dentry->d_name.len;
while (len-- > 0) {
c = *name - '0';
name++;
}
}
p = find_task_by_pid(pid);
- if (!pid || !p)
- return -ENOENT;
-
- ino = (pid << 16) + PROC_PID_INO;
- if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid)))
- 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;
+ }
+ d_add(dentry, inode);
return 0;
}
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;
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;
sysv_mknod, /* mknod */
sysv_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
sysv_bmap, /* bmap */
filp->f_reada = 1;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
return read;
}
pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
written += c;
buf += c;
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return written;
}
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;
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 */
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");
/* 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;
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;
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;
}
}
*p = tmp;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return result;
}
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);
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;
}
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)) {
}
} 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);
}
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;
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;
if (!dir_block) {
iput(dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -ENOSPC;
}
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);
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);
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);
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);
if (!name_block) {
iput(dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -ENOSPC;
}
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);
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;
iput(dir);
oldinode->i_nlink++;
oldinode->i_ctime = CURRENT_TIME;
- oldinode->i_dirt = 1;
+ mark_inode_dirty(oldinode);
iput(oldinode);
return 0;
}
* 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;
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;
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;
}
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);
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;
* 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;
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;
#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...
NULL, /* mknod */
NULL, /* rename */
sysv_readlink, /* readlink */
+ sysv_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
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;
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;
continue;
}
*p = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
brelse(bh);
sysv_free_block(sb,block);
}
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);
}
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
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"));
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;
* 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;
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;
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);
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);
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 */
}
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++;
* to invalidate a dentry for some reason (NFS
* timeouts or autofs deletes).
*/
-inline void d_drop(struct dentry * dentry)
+static inline void d_drop(struct dentry * dentry)
{
list_del(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_hash);
extern void ext2_read_inode (struct inode *);
extern void ext2_write_inode (struct inode *);
extern void ext2_put_inode (struct inode *);
+extern void ext2_delete_inode (struct inode *);
extern int ext2_sync_inode (struct inode *);
extern void ext2_discard_prealloc (struct inode *);
/* namei.c */
extern void ext2_release (struct inode *, struct file *);
-extern int ext2_lookup (struct inode *,struct qstr *, struct inode **);
+extern int ext2_lookup (struct inode *, struct dentry *);
extern int ext2_create (struct inode *,struct dentry *,int);
extern int ext2_mkdir (struct inode *,struct dentry *,int);
extern int ext2_rmdir (struct inode *,struct dentry *);
unsigned long i_ino;
kdev_t i_dev;
- atomic_t i_count;
+ unsigned short i_count;
umode_t i_mode;
nlink_t i_nlink;
uid_t i_uid;
/* Inode state bits.. */
#define I_DIRTY 0
#define I_LOCK 1
+#define I_FREEING 2
extern void __mark_inode_dirty(struct inode *);
static inline void mark_inode_dirty(struct inode *inode)
struct inode_operations {
struct file_operations * default_file_ops;
int (*create) (struct inode *,struct dentry *,int);
- int (*lookup) (struct inode *,struct qstr *name,struct inode **);
+ int (*lookup) (struct inode *,struct dentry *);
int (*link) (struct inode *,struct inode *,struct dentry *);
int (*unlink) (struct inode *,struct dentry *);
int (*symlink) (struct inode *,struct dentry *,const char *);
struct super_operations {
void (*read_inode) (struct inode *);
- int (*notify_change) (struct inode *, struct iattr *);
void (*write_inode) (struct inode *);
void (*put_inode) (struct inode *);
+ void (*delete_inode) (struct inode *);
+ int (*notify_change) (struct inode *, struct iattr *);
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
int (*statfs) (struct super_block *, struct statfs *, int);
extern struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino);
extern void insert_inode_hash(struct inode *);
-extern struct inode * get_pipe_inode(void);
extern int get_unused_fd(void);
extern void put_unused_fd(int);
extern struct file * get_empty_filp(void);
extern int isofs_open(struct inode * inode, struct file * filp);
extern void isofs_release(struct inode * inode, struct file * filp);
-extern int isofs_lookup(struct inode * dir, struct qstr *dentry,
- struct inode ** result);
+extern int isofs_lookup(struct inode * dir, struct dentry *);
extern unsigned long isofs_count_free_inodes(struct super_block *sb);
extern int isofs_new_block(int dev);
extern int isofs_free_block(int dev, int block);
*/
struct iso_inode_info {
unsigned int i_first_extent;
- unsigned int i_backlink;
unsigned char i_file_format;
};
extern void minix_read_inode(struct inode *);
extern void minix_write_inode(struct inode *);
extern void minix_put_inode(struct inode *);
-extern void minix_statfs(struct super_block *, struct statfs *, int);
+extern int minix_statfs(struct super_block *, struct statfs *, int);
extern int minix_sync_inode(struct inode *);
extern int minix_sync_file(struct inode *, struct file *);
extern void fat_read_inode(struct inode *inode, struct inode_operations *dir_ops);
extern struct super_block *fat_read_super(struct super_block *s, void *data, int silent);
extern void msdos_put_super(struct super_block *sb);
-extern void fat_statfs(struct super_block *sb,struct statfs *buf, int);
+extern int fat_statfs(struct super_block *sb,struct statfs *buf, int);
extern void fat_write_inode(struct inode *inode);
/* dir.c */
typedef struct svc_fh {
struct knfs_fh fh_handle; /* FH data */
struct svc_export * fh_export; /* export pointer */
- struct inode * fh_inode; /* inode */
+ struct dentry * fh_dentry; /* file */
size_t fh_pre_size; /* size before operation */
time_t fh_pre_mtime; /* mtime before oper */
time_t fh_pre_ctime; /* ctime before oper */
static inline void
fh_lock(struct svc_fh *fhp)
{
- struct inode *inode = fhp->fh_inode;
+ struct inode *inode = fhp->fh_dentry->d_inode;
/*
dfprintk(FILEOP, "nfsd: fh_lock(%x/%ld) locked = %d\n",
static inline void
fh_unlock(struct svc_fh *fhp)
{
- struct inode *inode = fhp->fh_inode;
+ struct inode *inode = fhp->fh_dentry->d_inode;
if (fhp->fh_locked) {
if (!fhp->fh_post_version)
static inline void
fh_put(struct svc_fh *fhp)
{
- if (fhp->fh_inode) {
+ if (fhp->fh_dentry) {
fh_unlock(fhp);
- iput(fhp->fh_inode);
+ dput(fhp->fh_dentry);
}
}
#else
static inline void
__fh_put(struct svc_fh *fhp, char *file, int line)
{
- struct inode *inode;
+ struct dentry *dentry;
- if (!(inode = fhp->fh_inode))
+ if (!(dentry = fhp->fh_dentry))
return;
- if (!atomic_read(&inode->i_count)) {
- printk("nfsd: trying to free free inode in %s:%d\n"
- " dev %04x ino %ld, mode %07o\n",
- file, line, inode->i_dev,
- inode->i_ino, inode->i_mode);
+ if (!dentry->d_count) {
+ printk("nfsd: trying to free free dentry in %s:%d\n"
+ " file %s/%s\n",
+ file, line,
+ dentry->d_parent->d_name.name, dentry->d_name.name);
} else {
fh_unlock(fhp);
- iput(inode);
+ dput(dentry);
}
}
#endif
struct wait_queue * wait;
char * base;
unsigned int start;
- unsigned int len;
unsigned int lock;
unsigned int rd_openers;
unsigned int wr_openers;
#define PIPE_WAIT(inode) ((inode).u.pipe_i.wait)
#define PIPE_BASE(inode) ((inode).u.pipe_i.base)
#define PIPE_START(inode) ((inode).u.pipe_i.start)
-#define PIPE_LEN(inode) ((inode).u.pipe_i.len)
+#define PIPE_LEN(inode) ((inode).i_size)
#define PIPE_RD_OPENERS(inode) ((inode).u.pipe_i.rd_openers)
#define PIPE_WR_OPENERS(inode) ((inode).u.pipe_i.wr_openers)
#define PIPE_READERS(inode) ((inode).u.pipe_i.readers)
* of the /proc/<pid> subdirectories.
*/
extern int proc_readdir(struct inode *, struct file *, void *, filldir_t);
-extern int proc_lookup(struct inode *, struct qstr *, struct inode **);
+extern int proc_lookup(struct inode *, struct dentry *);
struct openpromfs_dev {
struct openpromfs_dev *next;
const char * symname);
extern int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
extern int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
-extern 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);
+extern int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry);
extern struct inode * sysv_new_inode(const struct inode * dir);
extern void sysv_free_inode(struct inode * inode);
extern unsigned long sysv_count_free_inodes(struct super_block *sb);
extern int sysv_notify_change(struct inode *, struct iattr *);
extern void sysv_write_inode(struct inode *);
extern void sysv_put_inode(struct inode *);
-extern void sysv_statfs(struct super_block *, struct statfs *, int);
+extern int sysv_statfs(struct super_block *, struct statfs *, int);
extern int sysv_sync_inode(struct inode *);
extern int sysv_sync_file(struct inode *, struct file *);
extern int sysv_mmap(struct inode *, struct file *, struct vm_area_struct *);
EXPORT_SYMBOL(posix_test_lock);
EXPORT_SYMBOL(posix_block_lock);
EXPORT_SYMBOL(posix_unblock_lock);
+EXPORT_SYMBOL(dput);
#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
EXPORT_SYMBOL(do_nfsservctl);
return -ENFILE;
}
+ file->f_dentry = d_alloc_root(inode, NULL);
+ if (!file->f_dentry) {
+ put_filp(file);
+ put_unused_fd(fd);
+ return -ENOMEM;
+ }
+
+ /*
+ * The socket maintains a reference to the inode, so we
+ * have to increment the count.
+ */
+ inode->i_count++;
+
current->files->fd[fd] = file;
file->f_op = &socket_file_ops;
file->f_mode = 3;
err = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
inode = dentry->d_inode;
- atomic_inc(&inode->i_count);
+ inode->i_count++; /* HATEFUL - we should use the dentry */
dput(dentry);
err = 0;
}
}
if (sk->protinfo.af_unix.inode)
{
- atomic_inc(&sk->protinfo.af_unix.inode->i_count);
+ sk->protinfo.af_unix.inode->i_count++; /* Should use dentry */
newsk->protinfo.af_unix.inode=sk->protinfo.af_unix.inode;
}