}
if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
- d_delete(s->s_root);
+ dput(s->s_root);
s->s_dev = 0;
kfree(sbi);
printk("autofs: called with bogus options\n");
}
if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
- d_delete(s->s_root);
+ dput(s->s_root);
s->s_dev = 0;
kfree(sbi);
printk("autofs: kernel does not match daemon version\n");
} else {
printk("autofs: could not open pipe file descriptor\n");
}
- d_delete(s->s_root);
+ dput(s->s_root);
s->s_dev = 0;
kfree(sbi);
MOD_DEC_USE_COUNT;
return 0;
}
+/*
+ * 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;
autofs_hash_delete(ent);
clear_bit(n,sbi->symlink_bitmap);
kfree(sbi->symlink[n].data);
- d_delete(dentry);
+ d_drop(dentry);
return 0;
}
autofs_hash_delete(ent);
dir->i_nlink--;
- d_delete(dentry);
+ d_drop(dentry);
return 0;
}
dentry->d_name.name = str;
dentry->d_name.len = name->len;
dentry->d_name.hash = name->hash;
+ dentry->d_revalidate = NULL;
return dentry;
}
dput(parent);
}
+
/*
* When a file is deleted, we have two options:
* - turn this dentry into a negative dentry
}
/*
- * If not, just unhash us and wait for dput()
- * to pick up the tab..
+ * If not, just drop the dentry and let dput
+ * pick up the tab..
*/
- list_del(&dentry->d_hash);
- INIT_LIST_HEAD(&dentry->d_hash);
-
+ d_drop(dentry);
}
void d_add(struct dentry * entry, struct inode * inode)
es->s_free_inodes_count =
cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
- mark_inode_dirty(inode);
}
mark_buffer_dirty(bh, 1);
if (sb->s_flags & MS_SYNCHRONOUS) {
{
static unsigned long last_ino = 0;
struct inode * inode;
- struct list_head * tmp = inode_unused.next;
+ struct list_head * tmp;
+ spin_lock(&inode_lock);
+ 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_list);
INIT_LIST_HEAD(&inode->i_hash);
inode->i_sb = NULL;
inode->i_ino = ++last_ino;
atomic_set(&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;
}
/*
* Warning: if this succeeded, we will now
- * return with the inode lock, and we need to
- * unlock it.
+ * return with the inode lock.
*/
+ spin_unlock(&inode_lock);
inode = grow_inodes();
- if (inode) {
- spin_unlock(&inode_lock);
+ if (inode)
goto add_new_inode;
- }
+
return inode;
}
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;
*/
if (atomic_read(&inode->i_count) == 1) {
void (*put)(struct inode *);
+
+ if (inode->i_pipe) {
+ free_page((unsigned long)PIPE_BASE(*inode));
+ PIPE_BASE(*inode)= NULL;
+ }
+
if (inode->i_sb && inode->i_sb->s_op) {
put = inode->i_sb->s_op->put_inode;
if (put)
return 1;
}
-int fs_may_umount(kdev_t dev, struct dentry * root)
+int fs_may_umount(struct super_block *sb, struct dentry * root)
{
shrink_dcache();
return root->d_count == 1;
}
-int fs_may_remount_ro(kdev_t dev)
+int fs_may_remount_ro(struct super_block *sb)
{
- return 0;
+ return 1;
}
struct dentry * dentry = d_lookup(parent, name);
if (dentry) {
- /*
- * FIXME! We should have something like
-
- dentry = dentry->revalidate(dentry);
-
- * here - we need to ask the low-level filesystem permission
- * to use the cached entry (NFS needs to time them out, and
- * /proc might go away etc).
- */
+ if (dentry->d_revalidate)
+ dentry = dentry->d_revalidate(dentry);
/*
* The parent d_count _should_ be at least 2: one for the
* 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_root))
+ if (!fs_may_umount(sb, sb->s_root))
return -EBUSY;
/* clean up dcache .. */
/*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) {
struct list_head d_alias; /* inode alias list */
struct list_head d_lru; /* d_count = 0 LRU list */
struct qstr d_name;
+ struct dentry * (*d_revalidate)(struct dentry *);
};
+/*
+ * d_drop() unhashes the entry from the parent
+ * dentry hashes, so that it won't be found through
+ * a VFS lookup any more. Note that this is different
+ * from deleting the dentry - d_delete will try to
+ * mark the dentry negative if possible, giving a
+ * successful _negative_ lookup, while d_drop will
+ * just make the cache lookup fail.
+ *
+ * d_drop() is used mainly for stuff that wants
+ * to invalidate a dentry for some reason (NFS
+ * timeouts or autofs deletes).
+ */
+inline void d_drop(struct dentry * dentry)
+{
+ list_del(&dentry->d_hash);
+ INIT_LIST_HEAD(&dentry->d_hash);
+}
+
/*
* These are the low-level FS interfaces to the dcache..
*/
extern struct file_system_type *get_fs_type(const char *name);
extern int fs_may_mount(kdev_t dev);
-extern int fs_may_umount(kdev_t dev, struct dentry * root);
-extern int fs_may_remount_ro(kdev_t dev);
+extern int fs_may_umount(struct super_block *, struct dentry * root);
+extern int fs_may_remount_ro(struct super_block *);
extern struct file *inuse_filps;
extern struct super_block super_blocks[NR_SUPER];
EXPORT_SYMBOL(open_namei);
EXPORT_SYMBOL(sys_close);
EXPORT_SYMBOL(close_fp);
+EXPORT_SYMBOL(d_alloc_root);
+EXPORT_SYMBOL(d_delete);
EXPORT_SYMBOL(insert_file_free);
EXPORT_SYMBOL(check_disk_change);
EXPORT_SYMBOL(invalidate_buffers);