summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-06-15 01:55:58 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-06-15 01:55:58 +0000
commit53b3988d474435254a3b053a68bb24ce9e439295 (patch)
treef8da8e40f01f4ad02bbd76b8c9920749b118235f /fs
parentb0cb48abe83d1a4389ea938bf624f8baa82c5047 (diff)
Merge with 2.3.99-pre9.
Diffstat (limited to 'fs')
-rw-r--r--fs/Makefile14
-rw-r--r--fs/affs/namei.c2
-rw-r--r--fs/autofs/dir.c27
-rw-r--r--fs/autofs/dirhash.c4
-rw-r--r--fs/autofs4/root.c66
-rw-r--r--fs/bfs/dir.c6
-rw-r--r--fs/binfmt_aout.c4
-rw-r--r--fs/buffer.c16
-rw-r--r--fs/coda/cache.c44
-rw-r--r--fs/coda/dir.c10
-rw-r--r--fs/coda/psdev.c2
-rw-r--r--fs/cramfs/inode.c57
-rw-r--r--fs/dcache.c123
-rw-r--r--fs/devfs/base.c822
-rw-r--r--fs/devfs/util.c73
-rw-r--r--fs/exec.c69
-rw-r--r--fs/ext2/balloc.c2
-rw-r--r--fs/ext2/namei.c2
-rw-r--r--fs/hfs/balloc.c2
-rw-r--r--fs/hfs/catalog.c8
-rw-r--r--fs/hfs/dir.c2
-rw-r--r--fs/hfs/file_hdr.c2
-rw-r--r--fs/hfs/hfs.h16
-rw-r--r--fs/hfs/hfs_btree.h4
-rw-r--r--fs/hfs/mdb.c2
-rw-r--r--fs/hfs/part_tbl.c2
-rw-r--r--fs/hpfs/namei.c2
-rw-r--r--fs/inode.c4
-rw-r--r--fs/lockd/clntproc.c36
-rw-r--r--fs/lockd/svclock.c6
-rw-r--r--fs/minix/namei.c2
-rw-r--r--fs/msdos/namei.c2
-rw-r--r--fs/namei.c10
-rw-r--r--fs/ncpfs/dir.c25
-rw-r--r--fs/nfs/dir.c656
-rw-r--r--fs/nfs/inode.c29
-rw-r--r--fs/nfs/nfs2xdr.c7
-rw-r--r--fs/nfs/nfs3proc.c18
-rw-r--r--fs/nfs/proc.c18
-rw-r--r--fs/nfs/read.c21
-rw-r--r--fs/nfs/write.c63
-rw-r--r--fs/nfsd/nfscache.c7
-rw-r--r--fs/nfsd/nfsfh.c8
-rw-r--r--fs/openpromfs/inode.c3
-rw-r--r--fs/partitions/check.c3
-rw-r--r--fs/pipe.c3
-rw-r--r--fs/proc/base.c70
-rw-r--r--fs/proc/generic.c11
-rw-r--r--fs/proc/kcore.c17
-rw-r--r--fs/proc/proc_devtree.c1
-rw-r--r--fs/proc/root.c29
-rw-r--r--fs/qnx4/namei.c2
-rw-r--r--fs/ramfs/inode.c62
-rw-r--r--fs/readdir.c47
-rw-r--r--fs/smbfs/dir.c13
-rw-r--r--fs/smbfs/file.c23
-rw-r--r--fs/smbfs/proc.c45
-rw-r--r--fs/super.c102
-rw-r--r--fs/sysv/namei.c2
-rw-r--r--fs/udf/namei.c30
-rw-r--r--fs/ufs/namei.c2
-rw-r--r--fs/umsdos/Makefile2
-rw-r--r--fs/umsdos/check.c229
-rw-r--r--fs/umsdos/dir.c6
-rw-r--r--fs/umsdos/inode.c8
-rw-r--r--fs/umsdos/ioctl.c4
-rw-r--r--fs/umsdos/namei.c19
-rw-r--r--fs/umsdos/rdir.c2
-rw-r--r--fs/vfat/namei.c21
69 files changed, 1398 insertions, 1653 deletions
diff --git a/fs/Makefile b/fs/Makefile
index 9219a138f..0693daf69 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -21,7 +21,7 @@ ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
nfsd nls devpts devfs adfs partitions qnx4 udf bfs cramfs \
openpromfs autofs4 ramfs
-SUB_DIRS := partitions
+SUB_DIRS :=
ifeq ($(CONFIG_QUOTA),y)
O_OBJS += dquot.o
@@ -29,6 +29,14 @@ else
O_OBJS += noquot.o
endif
+ifdef CONFIG_PROC_FS
+SUB_DIRS += proc
+endif
+
+SUB_DIRS += partitions
+
+# Do not add any filesystems before this line
+
ifeq ($(CONFIG_EXT2_FS),y)
SUB_DIRS += ext2
else
@@ -93,10 +101,6 @@ else
endif
endif
-ifdef CONFIG_PROC_FS
-SUB_DIRS += proc
-endif
-
ifeq ($(CONFIG_BFS_FS),y)
SUB_DIRS += bfs
else
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index c1a849a70..e81e321e3 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -249,7 +249,6 @@ affs_unlink(struct inode *dir, struct dentry *dentry)
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_version = ++event;
mark_inode_dirty(inode);
- d_delete(dentry);
mark_inode_dirty(dir);
retval = 0;
@@ -380,7 +379,6 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
dir->i_version = ++event;
mark_inode_dirty(dir);
mark_inode_dirty(inode);
- d_delete(dentry);
rmdir_done:
affs_brelse(bh);
diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c
index b71c3a819..9c114f1c2 100644
--- a/fs/autofs/dir.c
+++ b/fs/autofs/dir.c
@@ -12,29 +12,10 @@
#include "autofs_i.h"
-static int autofs_dir_readdir(struct file *filp,
- void *dirent, filldir_t filldir)
-{
- struct inode *inode=filp->f_dentry->d_inode;
-
- switch((unsigned long) filp->f_pos)
- {
- case 0:
- if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0)
- return 0;
- filp->f_pos++;
- /* fall through */
- case 1:
- if (filldir(dirent, "..", 2, 1, AUTOFS_ROOT_INO) < 0)
- return 0;
- filp->f_pos++;
- /* fall through */
- }
- return 1;
-}
-
/*
- * No entries except for "." and "..", both of which are handled by the VFS layer
+ * No entries except for "." and "..", both of which are handled by the VFS
+ * layer. So all children are negative and dcache-based versions of operations
+ * are OK.
*/
static struct dentry *autofs_dir_lookup(struct inode *dir,struct dentry *dentry)
{
@@ -44,7 +25,7 @@ static struct dentry *autofs_dir_lookup(struct inode *dir,struct dentry *dentry)
struct file_operations autofs_dir_operations = {
read: generic_read_dir,
- readdir: autofs_dir_readdir,
+ readdir: dcache_readdir,
};
struct inode_operations autofs_dir_inode_operations = {
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
index 168d7861b..448143fd0 100644
--- a/fs/autofs/dirhash.c
+++ b/fs/autofs/dirhash.c
@@ -133,8 +133,8 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
autofs_say(ent->name,ent->len);
autofs_init_usage(dh,ent);
- if ( ent->dentry )
- ent->dentry->d_count++;
+ if (ent->dentry)
+ dget(ent->dentry);
dhnp = &dh->h[(unsigned) ent->hash % AUTOFS_HASH_SIZE];
ent->next = *dhnp;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 7f7337802..00951bf8e 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -16,7 +16,6 @@
#include <linux/param.h>
#include "autofs_i.h"
-static int autofs4_dir_readdir(struct file *,void *,filldir_t);
static struct dentry *autofs4_dir_lookup(struct inode *,struct dentry *);
static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
static int autofs4_dir_unlink(struct inode *,struct dentry *);
@@ -27,13 +26,13 @@ static struct dentry *autofs4_root_lookup(struct inode *,struct dentry *);
struct file_operations autofs4_root_operations = {
read: generic_read_dir,
- readdir: autofs4_dir_readdir,
+ readdir: dcache_readdir,
ioctl: autofs4_root_ioctl,
};
struct file_operations autofs4_dir_operations = {
read: generic_read_dir,
- readdir: autofs4_dir_readdir,
+ readdir: dcache_readdir,
};
struct inode_operations autofs4_root_inode_operations = {
@@ -52,67 +51,6 @@ struct inode_operations autofs4_dir_inode_operations = {
rmdir: autofs4_dir_rmdir,
};
-static inline struct dentry *nth_child(struct dentry *dir, int nr)
-{
- struct list_head *tmp = dir->d_subdirs.next;
-
- while(tmp != &dir->d_subdirs) {
- if (nr-- == 0)
- return list_entry(tmp, struct dentry, d_child);
- tmp = tmp->next;
- }
- return NULL;
-}
-
-static int autofs4_dir_readdir(struct file *filp, void *dirent,
- filldir_t filldir)
-{
- struct autofs_sb_info *sbi;
- struct autofs_info *ino;
- struct dentry *dentry = filp->f_dentry;
- struct dentry *dent_ptr;
- struct inode *dir = dentry->d_inode;
- struct list_head *cursor;
- off_t nr;
-
- sbi = autofs4_sbi(dir->i_sb);
- ino = autofs4_dentry_ino(dentry);
- nr = filp->f_pos;
-
- switch(nr)
- {
- case 0:
- if (filldir(dirent, ".", 1, nr, dir->i_ino) < 0)
- return 0;
- filp->f_pos = ++nr;
- /* fall through */
- case 1:
- if (filldir(dirent, "..", 2, nr, dentry->d_parent->d_inode->i_ino) < 0)
- return 0;
- filp->f_pos = ++nr;
- /* fall through */
- default:
- dent_ptr = nth_child(dentry, nr-2);
- if (dent_ptr == NULL)
- break;
-
- cursor = &dent_ptr->d_child;
-
- while(cursor != &dentry->d_subdirs) {
- dent_ptr = list_entry(cursor, struct dentry, d_child);
- if (dent_ptr->d_inode &&
- filldir(dirent, dent_ptr->d_name.name, dent_ptr->d_name.len, nr,
- dent_ptr->d_inode->i_ino) < 0)
- return 0;
- filp->f_pos = ++nr;
- cursor = cursor->next;
- }
- break;
- }
-
- return 0;
-}
-
/* Update usage from here to top of tree, so that scan of
top-level directories will give a useful result */
static void autofs4_update_usage(struct dentry *dentry)
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 38881a1b6..bd8be88c3 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -32,11 +32,6 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
unsigned int offset;
int block;
- if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
- printf("Bad inode or not a directory %s:%08lx\n", bdevname(dev), dir->i_ino);
- return -EBADF;
- }
-
if (f->f_pos & (BFS_DIRENT_SIZE-1)) {
printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f->f_pos,
bdevname(dev), dir->i_ino);
@@ -188,7 +183,6 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
mark_inode_dirty(inode);
- d_delete(dentry);
error = 0;
out_brelse:
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 49d818e21..ef4af4dfe 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -86,6 +86,8 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
struct user dump;
#if defined(__alpha__)
# define START_DATA(u) (u.start_data)
+#elif defined(__arm__)
+# define START_DATA(u) ((u.u_tsize << PAGE_SHIFT) + u.start_code)
#elif defined(__sparc__)
# define START_DATA(u) (u.u_tsize)
#elif defined(__i386__) || defined(__mc68000__)
@@ -217,7 +219,7 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
envp = (char **) sp;
sp -= argc+1;
argv = (char **) sp;
-#if defined(__i386__) || defined(__mc68000__)
+#if defined(__i386__) || defined(__mc68000__) || defined(__arm__)
put_user((unsigned long) envp,--sp);
put_user((unsigned long) argv,--sp);
#endif
diff --git a/fs/buffer.c b/fs/buffer.c
index a7a6f79a8..47d690fa4 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1324,7 +1324,7 @@ int block_flushpage(struct page *page, unsigned long offset)
* instead.
*/
if (!offset) {
- if (!try_to_free_buffers(page)) {
+ if (!try_to_free_buffers(page, 0)) {
atomic_inc(&buffermem_pages);
return 0;
}
@@ -2121,15 +2121,17 @@ out:
* This all is required so that we can free up memory
* later.
*/
-static void sync_page_buffers(struct buffer_head *bh)
+static void sync_page_buffers(struct buffer_head *bh, int wait)
{
- struct buffer_head * tmp;
+ struct buffer_head * tmp = bh;
- tmp = bh;
do {
struct buffer_head *p = tmp;
tmp = tmp->b_this_page;
- if (buffer_dirty(p) && !buffer_locked(p))
+ if (buffer_locked(p)) {
+ if (wait)
+ __wait_on_buffer(p);
+ } else if (buffer_dirty(p))
ll_rw_block(WRITE, 1, &p);
} while (tmp != bh);
}
@@ -2151,7 +2153,7 @@ static void sync_page_buffers(struct buffer_head *bh)
* obtain a reference to a buffer head within a page. So we must
* lock out all of these paths to cleanly toss the page.
*/
-int try_to_free_buffers(struct page * page)
+int try_to_free_buffers(struct page * page, int wait)
{
struct buffer_head * tmp, * bh = page->buffers;
int index = BUFSIZE_INDEX(bh->b_size);
@@ -2201,7 +2203,7 @@ busy_buffer_page:
spin_unlock(&free_list[index].lock);
write_unlock(&hash_table_lock);
spin_unlock(&lru_list_lock);
- sync_page_buffers(bh);
+ sync_page_buffers(bh, wait);
return 0;
}
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index fa8a66e0c..68be7a69d 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -259,8 +259,6 @@ int coda_cache_check(struct inode *inode, int mask)
void coda_purge_dentries(struct inode *inode)
{
- struct list_head *tmp, *head = &inode->i_dentry;
-
if (!inode)
return ;
@@ -268,23 +266,7 @@ void coda_purge_dentries(struct inode *inode)
iget(inode->i_sb, inode->i_ino);
/* catch the dentries later if some are still busy */
coda_flag_inode(inode, C_PURGE);
-
-restart:
- tmp = head;
- while ((tmp = tmp->next) != head) {
- struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
- if (!dentry->d_count) {
- CDEBUG(D_DOWNCALL,
- "coda_free_dentries: freeing %s/%s, i_count=%d\n",
- dentry->d_parent->d_name.name, dentry->d_name.name,
- inode->i_count);
- dget(dentry);
- d_drop(dentry);
- dput(dentry);
- goto restart;
- }
-
- }
+ d_prune_aliases(inode);
iput(inode);
}
@@ -311,28 +293,18 @@ static void coda_flag_children(struct dentry *parent, int flag)
void coda_flag_inode_children(struct inode *inode, int flag)
{
- struct list_head *alias;
struct dentry *alias_de;
ENTRY;
- if ( !inode )
+ if ( !inode || !S_ISDIR(inode->i_mode))
return;
- if (list_empty(&inode->i_dentry))
- return;
-
- /* I believe that shrink_dcache_parent will not
- remove dentries from the alias list. If it
- does we are toast.
- */
- alias = inode->i_dentry.next;
- while ( alias != &inode->i_dentry ) {
- alias_de = list_entry(alias, struct dentry, d_alias);
- coda_flag_children(alias_de, flag);
- alias = alias->next;
- shrink_dcache_parent(alias_de);
- }
-
+ alias_de = d_find_alias(inode);
+ if (!alias_de)
+ return;
+ coda_flag_children(alias_de, flag);
+ shrink_dcache_parent(alias_de);
+ dput(alias_de);
}
/* this will not zap the inode away */
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index bb51b0c05..83f7bbcc5 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -45,7 +45,7 @@ static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
/* dentry ops */
static int coda_dentry_revalidate(struct dentry *de, int);
-static void coda_dentry_delete(struct dentry *);
+static int coda_dentry_delete(struct dentry *);
/* support routines */
static int coda_venus_readdir(struct file *filp, void *dirent,
@@ -434,7 +434,6 @@ int coda_unlink(struct inode *dir, struct dentry *de)
/* cache management: mtime has changed, ask Venus */
dircnp->c_flags |= C_VATTR;
de->d_inode->i_nlink--;
- d_delete(de);
return 0;
}
@@ -801,20 +800,21 @@ static int coda_dentry_revalidate(struct dentry *de, int flags)
* This is the callback from dput() when d_count is going to 0.
* We use this to unhash dentries with bad inodes.
*/
-static void coda_dentry_delete(struct dentry * dentry)
+static int coda_dentry_delete(struct dentry * dentry)
{
int flags;
if (!dentry->d_inode)
- return ;
+ return 0;
flags = (ITOC(dentry->d_inode)->c_flags) & C_PURGE;
if (is_bad_inode(dentry->d_inode) || flags) {
CDEBUG(D_DOWNCALL, "bad inode, unhashing %s/%s, %ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
dentry->d_inode->i_ino);
- d_drop(dentry);
+ return 1;
}
+ return 0;
}
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 1a7fb195c..b88c602c6 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -296,6 +296,8 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
vcp->vc_inuse, vcp->vc_pid, current->pid);
if ( vcp->vc_pid != current->pid ) {
+ /* FIXME: this is broken. If venus does fork(), accounting goes wrong */
+ printk( "Closed by someone else than caller?\n" );
return 0;
}
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 279b0bfef..3f51c2aa1 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -84,15 +84,17 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
#define NEXT_BUFFER(_ix) ((_ix) ^ 1)
/*
- * BLKS_PER_BUF_SHIFT must be at least 1 to allow for "compressed"
- * data that takes up more space than the original. 1 is guaranteed
- * to suffice, though. Larger values provide more read-ahead and
- * proportionally less wastage at the end of the buffer.
+ * BLKS_PER_BUF_SHIFT should be at least 2 to allow for "compressed"
+ * data that takes up more space than the original and with unlucky
+ * alignment.
*/
-#define BLKS_PER_BUF_SHIFT (2)
-#define BLKS_PER_BUF (1 << BLKS_PER_BUF_SHIFT)
-static unsigned char read_buffers[READ_BUFFERS][BLKS_PER_BUF][PAGE_CACHE_SIZE];
+#define BLKS_PER_BUF_SHIFT (2)
+#define BLKS_PER_BUF (1 << BLKS_PER_BUF_SHIFT)
+#define BUFFER_SIZE (BLKS_PER_BUF*PAGE_CACHE_SIZE)
+
+static unsigned char read_buffers[READ_BUFFERS][BUFFER_SIZE];
static unsigned buffer_blocknr[READ_BUFFERS];
+static struct super_block * buffer_dev[READ_BUFFERS];
static int next_buffer = 0;
/*
@@ -102,19 +104,27 @@ static int next_buffer = 0;
static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
{
struct buffer_head * bh_array[BLKS_PER_BUF];
- unsigned i, blocknr, last_blocknr, buffer;
+ unsigned i, blocknr, buffer;
+ char *data;
if (!len)
return NULL;
blocknr = offset >> PAGE_CACHE_SHIFT;
- last_blocknr = (offset + len - 1) >> PAGE_CACHE_SHIFT;
- if (last_blocknr - blocknr >= BLKS_PER_BUF)
- goto eek; resume:
offset &= PAGE_CACHE_SIZE - 1;
+
+ /* Check if an existing buffer already has the data.. */
for (i = 0; i < READ_BUFFERS; i++) {
- if ((blocknr >= buffer_blocknr[i]) &&
- (last_blocknr - buffer_blocknr[i] < BLKS_PER_BUF))
- return &read_buffers[i][blocknr - buffer_blocknr[i]][offset];
+ unsigned int blk_offset;
+
+ if (buffer_dev[i] != sb)
+ continue;
+ if (blocknr < buffer_blocknr[i])
+ continue;
+ blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;
+ blk_offset += offset;
+ if (blk_offset + len > BUFFER_SIZE)
+ continue;
+ return read_buffers[i] + blk_offset;
}
/* Ok, read in BLKS_PER_BUF pages completely first. */
@@ -125,24 +135,19 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i
buffer = next_buffer;
next_buffer = NEXT_BUFFER(buffer);
buffer_blocknr[buffer] = blocknr;
+ buffer_dev[buffer] = sb;
+
+ data = read_buffers[buffer];
for (i = 0; i < BLKS_PER_BUF; i++) {
struct buffer_head * bh = bh_array[i];
if (bh) {
- memcpy(read_buffers[buffer][i], bh->b_data, PAGE_CACHE_SIZE);
+ memcpy(data, bh->b_data, PAGE_CACHE_SIZE);
bforget(bh);
} else
- memset(read_buffers[buffer][i], 0, PAGE_CACHE_SIZE);
+ memset(data, 0, PAGE_CACHE_SIZE);
+ data += PAGE_CACHE_SIZE;
}
- return read_buffers[buffer][0] + offset;
-
- eek:
- printk(KERN_ERR
- "cramfs (device %s): requested chunk (%u:+%u) bigger than buffer\n",
- bdevname(sb->s_dev), offset, len);
- /* TODO: return EIO to process or kill the current process
- instead of resuming. */
- *((int *)0) = 0; /* XXX: doesn't work on all archs */
- goto resume;
+ return read_buffers[buffer] + offset;
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 1b3ff98b2..ad897ff38 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -131,7 +131,8 @@ repeat:
* Each fs will have to watch for this.
*/
if (dentry->d_op && dentry->d_op->d_delete) {
- dentry->d_op->d_delete(dentry);
+ if (dentry->d_op->d_delete(dentry))
+ d_drop(dentry);
count = dentry->d_count - 1;
if (count != 0)
@@ -220,6 +221,53 @@ int d_invalidate(struct dentry * dentry)
return 0;
}
+/**
+ * d_find_alias - grab a hashed alias of inode
+ * @inode: inode in question
+ *
+ * If inode has a hashed alias - acquire the reference to alias and
+ * return it. Otherwise return NULL. Notice that if inode is a directory
+ * there can be only one alias and it can be unhashed only if it has
+ * no children.
+ */
+
+struct dentry * d_find_alias(struct inode *inode)
+{
+ struct list_head *head, *next, *tmp;
+ struct dentry *alias;
+
+ head = &inode->i_dentry;
+ next = inode->i_dentry.next;
+ while (next != head) {
+ tmp = next;
+ next = tmp->next;
+ alias = list_entry(tmp, struct dentry, d_alias);
+ if (!d_unhashed(alias))
+ return dget(alias);
+ }
+ return NULL;
+}
+
+/*
+ * Try to kill dentries associated with this inode.
+ * WARNING: you must own a reference to inode.
+ */
+void d_prune_aliases(struct inode *inode)
+{
+ struct list_head *tmp, *head = &inode->i_dentry;
+restart:
+ tmp = head;
+ while ((tmp = tmp->next) != head) {
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
+ if (!dentry->d_count) {
+ dget(dentry);
+ d_drop(dentry);
+ dput(dentry);
+ goto restart;
+ }
+ }
+}
+
/*
* Throw away a dentry - free the inode, dput the parent.
* This requires that the LRU list has already been
@@ -384,37 +432,6 @@ resume:
return 0; /* No mount points found in tree */
}
-int d_active_refs(struct dentry *root)
-{
- struct dentry *this_parent = root;
- struct list_head *next;
- int count = root->d_count;
-
-repeat:
- next = this_parent->d_subdirs.next;
-resume:
- while (next != &this_parent->d_subdirs) {
- struct list_head *tmp = next;
- struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
- next = tmp->next;
- /* Decrement count for unused children */
- count += (dentry->d_count - 1);
- if (!list_empty(&dentry->d_subdirs)) {
- this_parent = dentry;
- goto repeat;
- }
- }
- /*
- * All done at this level ... ascend and resume the search.
- */
- if (this_parent != root) {
- next = this_parent->d_child.next;
- this_parent = this_parent->d_parent;
- goto resume;
- }
- return count;
-}
-
/*
* Search the dentry child list for the specified parent,
* and move any unused dentries to the end of the unused
@@ -788,7 +805,7 @@ void d_rehash(struct dentry * entry)
* Note that we have to be a lot more careful about getting the hash
* switched - we have to switch the hash value properly even if it
* then no longer matches the actual (corrupted) string of the target.
- * The has value has to match the hash queue that the dentry is on..
+ * The hash value has to match the hash queue that the dentry is on..
*/
static inline void switch_names(struct dentry * dentry, struct dentry * target)
{
@@ -948,7 +965,12 @@ global_root:
asmlinkage long sys_getcwd(char *buf, unsigned long size)
{
int error;
- struct dentry *pwd = current->fs->pwd;
+ struct vfsmount *pwdmnt;
+ struct dentry *pwd;
+
+ lock_kernel();
+ pwdmnt = mntget(current->fs->pwdmnt);
+ pwd = dget(current->fs->pwd);
error = -ENOENT;
/* Has the current directory has been unlinked? */
@@ -959,9 +981,7 @@ asmlinkage long sys_getcwd(char *buf, unsigned long size)
unsigned long len;
char * cwd;
- lock_kernel();
cwd = d_path(pwd, current->fs->pwdmnt, page, PAGE_SIZE);
- unlock_kernel();
error = -ERANGE;
len = PAGE_SIZE + page - cwd;
@@ -973,6 +993,9 @@ asmlinkage long sys_getcwd(char *buf, unsigned long size)
free_page((unsigned long) page);
}
}
+ dput(pwd);
+ mntput(pwdmnt);
+ unlock_kernel();
return error;
}
@@ -1010,6 +1033,34 @@ int is_subdir(struct dentry * new_dentry, struct dentry * old_dentry)
return result;
}
+void d_genocide(struct dentry *root)
+{
+ struct dentry *this_parent = root;
+ struct list_head *next;
+
+repeat:
+ next = this_parent->d_subdirs.next;
+resume:
+ while (next != &this_parent->d_subdirs) {
+ struct list_head *tmp = next;
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+ next = tmp->next;
+ if (d_unhashed(dentry)||!dentry->d_inode)
+ continue;
+ if (!list_empty(&dentry->d_subdirs)) {
+ this_parent = dentry;
+ goto repeat;
+ }
+ dentry->d_count--;
+ }
+ if (this_parent != root) {
+ next = this_parent->d_child.next;
+ this_parent->d_count--;
+ this_parent = this_parent->d_parent;
+ goto resume;
+ }
+}
+
/**
* find_inode_number - check for dentry with name
* @dir: directory to check
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index 567156868..040e0b79a 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -555,7 +555,7 @@ typedef struct wait_queue *wait_queue_head_t;
#define OOPS(format, args...) {printk (format, ## args); \
printk ("Forcing Oops\n"); \
- *(int *) 0 = 0;}
+ BUG();}
struct directory_type
{
@@ -729,17 +729,21 @@ static struct file_operations devfsd_fops =
/* Support functions follow */
+
+/**
+ * search_for_entry_in_dir - Search for a devfs entry inside another devfs entry.
+ * @parent: The parent devfs entry.
+ * @name: The name of the entry.
+ * @namelen: The number of characters in @name.
+ * @traverse_symlink: If %TRUE then the entry is traversed if it is a symlink.
+ *
+ * Returns a pointer to the entry on success, else %NULL.
+ */
+
static struct devfs_entry *search_for_entry_in_dir (struct devfs_entry *parent,
const char *name,
unsigned int namelen,
int traverse_symlink)
-/* [SUMMARY] Search for a devfs entry inside another devfs entry.
- <parent> The parent devfs entry.
- <name> The name of the entry.
- <namelen> The number of characters in <<name>>.
- <traverse_symlink> If TRUE then the entry is traversed if it is a symlink.
- [RETURNS] A pointer to the entry on success, else NULL.
-*/
{
struct devfs_entry *curr;
@@ -783,10 +787,14 @@ static struct devfs_entry *create_entry (struct devfs_entry *parent,
return new;
} /* End Function create_entry */
+
+/**
+ * get_root_entry - Get the root devfs entry.
+ *
+ * Returns the root devfs entry on success, else %NULL.
+ */
+
static struct devfs_entry *get_root_entry (void)
-/* [SUMMARY] Get the root devfs entry.
- [RETURNS] The root devfs entry on success, else NULL.
-*/
{
struct devfs_entry *new;
@@ -809,23 +817,27 @@ static struct devfs_entry *get_root_entry (void)
return root_entry;
} /* End Function get_root_entry */
+
+/**
+ * search_for_entry - Search for an entry in the devfs tree.
+ * @dir: The parent directory to search from. If this is %NULL the root is used
+ * @name: The name of the entry.
+ * @namelen: The number of characters in @name.
+ * @mkdir: If %TRUE intermediate directories are created as needed.
+ * @mkfile: If %TRUE the file entry is created if it doesn't exist.
+ * @is_new: If the returned entry was newly made, %TRUE is written here. If
+ * this is %NULL nothing is written here.
+ * @traverse_symlink: If %TRUE then symbolic links are traversed.
+ *
+ * If the entry is created, then it will be in the unregistered state.
+ * Returns a pointer to the entry on success, else %NULL.
+ */
+
static struct devfs_entry *search_for_entry (struct devfs_entry *dir,
const char *name,
unsigned int namelen, int mkdir,
int mkfile, int *is_new,
int traverse_symlink)
-/* [SUMMARY] Search for an entry in the devfs tree.
- <dir> The parent directory to search from. If this is NULL the root is used
- <name> The name of the entry.
- <namelen> The number of characters in <<name>>.
- <mkdir> If TRUE intermediate directories are created as needed.
- <mkfile> If TRUE the file entry is created if it doesn't exist.
- <is_new> If the returned entry was newly made, TRUE is written here. If
- this is NULL nothing is written here.
- <traverse_symlink> If TRUE then symbolic links are traversed.
- [NOTE] If the entry is created, then it will be in the unregistered state.
- [RETURNS] A pointer to the entry on success, else NULL.
-*/
{
int len;
const char *subname, *stop, *ptr;
@@ -887,16 +899,20 @@ static struct devfs_entry *search_for_entry (struct devfs_entry *dir,
return NULL;
} /* End Function search_for_entry */
+
+/**
+ * find_by_dev - Find a devfs entry in a directory.
+ * @major: The major number to search for.
+ * @minor: The minor number to search for.
+ * @type: The type of special file to search for. This may be either
+ * %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
+ *
+ * Returns the devfs_entry pointer on success, else %NULL.
+ */
+
static struct devfs_entry *find_by_dev (struct devfs_entry *dir,
unsigned int major, unsigned int minor,
char type)
-/* [SUMMARY] Find a devfs entry in a directory.
- <major> The major number to search for.
- <minor> The minor number to search for.
- <type> The type of special file to search for. This may be either
- DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK.
- [RETURNS] The devfs_entry pointer on success, else NULL.
-*/
{
struct devfs_entry *entry, *de;
@@ -926,26 +942,31 @@ static struct devfs_entry *find_by_dev (struct devfs_entry *dir,
return NULL;
} /* End Function find_by_dev */
+
+/**
+ * find_entry - Find a devfs entry.
+ * @dir: The handle to the parent devfs directory entry. If this is %NULL the
+ * name is relative to the root of the devfs.
+ * @name: The name of the entry. This is ignored if @handle is not %NULL.
+ * @namelen: The number of characters in @name, not including a %NULL
+ * terminator. If this is 0, then @name must be %NULL-terminated and the
+ * length is computed internally.
+ * @major: The major number. This is used if @handle and @name are %NULL.
+ * @minor: The minor number. This is used if @handle and @name are %NULL.
+ * NOTE: If @major and @minor are both 0, searching by major and minor
+ * numbers is disabled.
+ * @type: The type of special file to search for. This may be either
+ * %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
+ * @traverse_symlink: If %TRUE then symbolic links are traversed.
+ *
+ * FIXME: What the hell is @handle? - ch
+ * Returns the devfs_entry pointer on success, else %NULL.
+ */
+
static struct devfs_entry *find_entry (devfs_handle_t dir,
const char *name, unsigned int namelen,
unsigned int major, unsigned int minor,
char type, int traverse_symlink)
-/* [SUMMARY] Find a devfs entry.
- <dir> The handle to the parent devfs directory entry. If this is NULL the
- name is relative to the root of the devfs.
- <name> The name of the entry. This is ignored if <<handle>> is not NULL.
- <namelen> The number of characters in <<name>>, not including a NULL
- terminator. If this is 0, then <<name>> must be NULL-terminated and the
- length is computed internally.
- <major> The major number. This is used if <<handle>> and <<name>> are NULL.
- <minor> The minor number. This is used if <<handle>> and <<name>> are NULL.
- [NOTE] If <<major>> and <<minor>> are both 0, searching by major and minor
- numbers is disabled.
- <type> The type of special file to search for. This may be either
- DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK.
- <traverse_symlink> If TRUE then symbolic links are traversed.
- [RETURNS] The devfs_entry pointer on success, else NULL.
-*/
{
struct devfs_entry *entry;
@@ -991,11 +1012,13 @@ static struct devfs_inode *get_devfs_inode_from_vfs_inode (struct inode *inode)
return fs_info->table[inode->i_ino - FIRST_INODE];
} /* End Function get_devfs_inode_from_vfs_inode */
+
+/**
+ * free_dentries - Free the dentries for a device entry and invalidate inodes.
+ * @de: The entry.
+ */
+
static void free_dentries (struct devfs_entry *de)
-/* [SUMMARY] Free the dentries for a device entry and invalidate inodes.
- <de> The entry.
- [RETURNS] Nothing.
-*/
{
struct devfs_inode *di;
struct dentry *dentry;
@@ -1015,11 +1038,15 @@ static void free_dentries (struct devfs_entry *de)
}
} /* End Function free_dentries */
+
+/**
+ * is_devfsd_or_child - Test if the current process is devfsd or one of its children.
+ * fs_info: The filesystem information.
+ *
+ * Returns %TRUE if devfsd or child, else %FALSE.
+ */
+
static int is_devfsd_or_child (struct fs_info *fs_info)
-/* [SUMMARY] Test if the current process is devfsd or one of its children.
- <fs_info> The filesystem information.
- [RETURNS] TRUE if devfsd or child, else FALSE.
-*/
{
struct task_struct *p;
@@ -1030,20 +1057,28 @@ static int is_devfsd_or_child (struct fs_info *fs_info)
return (FALSE);
} /* End Function is_devfsd_or_child */
+
+/**
+ * devfsd_queue_empty - Test if devfsd has work pending in its event queue.
+ * @fs_info: The filesystem information.
+ *
+ * Returns %TRUE if the queue is empty, else %FALSE.
+ */
+
static inline int devfsd_queue_empty (struct fs_info *fs_info)
-/* [SUMMARY] Test if devfsd has work pending in its event queue.
- <fs_info> The filesystem information.
- [RETURNS] TRUE if the queue is empty, else FALSE.
-*/
{
return (fs_info->devfsd_buf_out == fs_info->devfsd_buf_in) ? TRUE : FALSE;
} /* End Function devfsd_queue_empty */
+
+/**
+ * wait_for_devfsd_finished - Wait for devfsd to finish processing its event queue.
+ * @fs_info: The filesystem information.
+ *
+ * Returns %TRUE if no more waiting will be required, else %FALSE.
+ */
+
static int wait_for_devfsd_finished (struct fs_info *fs_info)
-/* [SUMMARY] Wait for devfsd to finish processing its event queue.
- <fs_info> The filesystem information.
- [RETURNS] TRUE if no more waiting will be required, else FALSE.
-*/
{
DECLARE_WAITQUEUE (wait, current);
@@ -1059,17 +1094,21 @@ static int wait_for_devfsd_finished (struct fs_info *fs_info)
return (TRUE);
} /* End Function wait_for_devfsd_finished */
+
+/**
+ * devfsd_notify_one - Notify a single devfsd daemon of a change.
+ * @data: Data to be passed.
+ * @type: The type of change.
+ * @mode: The mode of the entry.
+ * @uid: The user ID.
+ * @gid: The group ID.
+ * @fs_info: The filesystem info.
+ *
+ * Returns %TRUE if an event was queued and devfsd woken up, else %FALSE.
+ */
+
static int devfsd_notify_one (void *data, unsigned int type, umode_t mode,
uid_t uid, gid_t gid, struct fs_info *fs_info)
-/* [SUMMARY] Notify a single devfsd daemon of a change.
- <data> Data to be passed.
- <type> The type of change.
- <mode> The mode of the entry.
- <uid> The user ID.
- <gid> The group ID.
- <fs_info> The filesystem info.
- [RETURNS] TRUE if an event was queued and devfsd woken up, else FALSE.
-*/
{
unsigned int next_pos;
unsigned long flags;
@@ -1103,14 +1142,16 @@ static int devfsd_notify_one (void *data, unsigned int type, umode_t mode,
return (TRUE);
} /* End Function devfsd_notify_one */
+
+/**
+ * devfsd_notify - Notify all devfsd daemons of a change.
+ * @de: The devfs entry that has changed.
+ * @type: The type of change event.
+ * @wait: If TRUE, the functions waits for all daemons to finish processing
+ * the event.
+ */
+
static void devfsd_notify (struct devfs_entry *de, unsigned int type, int wait)
-/* [SUMMARY] Notify all devfsd daemons of a change.
- <de> The devfs entry that has changed.
- <type> The type of change event.
- <wait> If TRUE, the functions waits for all daemons to finish processing
- the event.
- [RETURNS] Nothing.
-*/
{
struct fs_info *fs_info;
@@ -1122,35 +1163,38 @@ static void devfsd_notify (struct devfs_entry *de, unsigned int type, int wait)
}
} /* End Function devfsd_notify */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_register - Register a device entry.
+ * @dir: The handle to the parent devfs directory entry. If this is %NULL the
+ * new name is relative to the root of the devfs.
+ * @name: The name of the entry.
+ * @namelen: The number of characters in @name, not including a %NULL
+ * terminator. If this is 0, then @name must be %NULL-terminated and the
+ * length is computed internally.
+ * @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
+ * @major: The major number. Not needed for regular files.
+ * @minor: The minor number. Not needed for regular files.
+ * @mode: The default file mode.
+ * @uid: The default UID of the file.
+ * @guid: The default GID of the file.
+ * @ops: The &file_operations or &block_device_operations structure.
+ * This must not be externally deallocated.
+ * @info: An arbitrary pointer which will be written to the @private_data
+ * field of the &file structure passed to the device driver. You can set
+ * this to whatever you like, and change it once the file is opened (the next
+ * file opened will not see this change).
+ *
+ * Returns a handle which may later be used in a call to devfs_unregister().
+ * On failure %NULL is returned.
+ */
+
devfs_handle_t devfs_register (devfs_handle_t dir,
const char *name, unsigned int namelen,
unsigned int flags,
unsigned int major, unsigned int minor,
umode_t mode, uid_t uid, gid_t gid,
void *ops, void *info)
-/* [SUMMARY] Register a device entry.
- <dir> The handle to the parent devfs directory entry. If this is NULL the
- new name is relative to the root of the devfs.
- <name> The name of the entry.
- <namelen> The number of characters in <<name>>, not including a NULL
- terminator. If this is 0, then <<name>> must be NULL-terminated and the
- length is computed internally.
- <flags> A set of bitwise-ORed flags (DEVFS_FL_*).
- <major> The major number. Not needed for regular files.
- <minor> The minor number. Not needed for regular files.
- <mode> The default file mode.
- <uid> The default UID of the file.
- <guid> The default GID of the file.
- <ops> The <<file_operations>> or <<block_device_operations>> structure.
- This must not be externally deallocated.
- <info> An arbitrary pointer which will be written to the <<private_data>>
- field of the <<file>> structure passed to the device driver. You can set
- this to whatever you like, and change it once the file is opened (the next
- file opened will not see this change).
- [RETURNS] A handle which may later be used in a call to
- [<devfs_unregister>]. On failure NULL is returned.
-*/
{
int is_new;
struct devfs_entry *de;
@@ -1276,11 +1320,13 @@ devfs_handle_t devfs_register (devfs_handle_t dir,
return de;
} /* End Function devfs_register */
+
+/**
+ * unregister - Unregister a device entry.
+ * @de: The entry to unregister.
+ */
+
static void unregister (struct devfs_entry *de)
-/* [SUMMARY] Unregister a device entry.
- <de> The entry to unregister.
- [RETURNS] Nothing.
-*/
{
struct devfs_entry *child;
@@ -1332,13 +1378,14 @@ static void unregister (struct devfs_entry *de)
}
} /* End Function unregister */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_unregister - Unregister a device entry.
+ * de: A handle previously created by devfs_register() or returned from
+ * devfs_find_handle(). If this is %NULL the routine does nothing.
+ */
+
void devfs_unregister (devfs_handle_t de)
-/* [SUMMARY] Unregister a device entry.
- <de> A handle previously created by [<devfs_register>] or returned from
- [<devfs_find_handle>]. If this is NULL the routine does nothing.
- [RETURNS] Nothing.
-*/
{
if (de == NULL) return;
#ifdef CONFIG_DEVFS_DEBUG
@@ -1349,28 +1396,31 @@ void devfs_unregister (devfs_handle_t de)
unregister (de);
} /* End Function devfs_unregister */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_mk_symlink Create a symbolic link in the devfs namespace.
+ * @dir: The handle to the parent devfs directory entry. If this is %NULL the
+ * new name is relative to the root of the devfs.
+ * @name: The name of the entry.
+ * @namelen: The number of characters in @name, not including a %NULL
+ * terminator. If this is 0, then @name must be %NULL-terminated and the
+ * length is computed internally.
+ * @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
+ * @link: The destination name.
+ * @linklength: The number of characters in @link, not including a %NULL
+ * terminator. If this is 0, then @link must be %NULL-terminated and the
+ * length is computed internally.
+ * @handle: The handle to the symlink entry is written here. This may be %NULL.
+ * @info: An arbitrary pointer which will be associated with the entry.
+ *
+ * Returns 0 on success, else a negative error code is returned.
+ */
+
int devfs_mk_symlink (devfs_handle_t dir,
const char *name, unsigned int namelen,
unsigned int flags,
const char *link, unsigned int linklength,
devfs_handle_t *handle, void *info)
-/* [SUMMARY] Create a symbolic link in the devfs namespace.
- <dir> The handle to the parent devfs directory entry. If this is NULL the
- new name is relative to the root of the devfs.
- <name> The name of the entry.
- <namelen> The number of characters in <<name>>, not including a NULL
- terminator. If this is 0, then <<name>> must be NULL-terminated and the
- length is computed internally.
- <flags> A set of bitwise-ORed flags (DEVFS_FL_*).
- <link> The destination name.
- <linklength> The number of characters in <<link>>, not including a NULL
- terminator. If this is 0, then <<link>> must be NULL-terminated and the
- length is computed internally.
- <handle> The handle to the symlink entry is written here. This may be NULL.
- <info> An arbitrary pointer which will be associated with the entry.
- [RETURNS] 0 on success, else a negative error code is returned.
-*/
{
int is_new;
char *newname;
@@ -1439,23 +1489,26 @@ int devfs_mk_symlink (devfs_handle_t dir,
return 0;
} /* End Function devfs_mk_symlink */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_mk_dir - Create a directory in the devfs namespace.
+ * @dir: The handle to the parent devfs directory entry. If this is %NULL the
+ * new name is relative to the root of the devfs.
+ * @name: The name of the entry.
+ * @namelen: The number of characters in @name, not including a %NULL
+ * terminator. If this is 0, then @name must be %NULL-terminated and the
+ * length is computed internally.
+ * @info: An arbitrary pointer which will be associated with the entry.
+ *
+ * Use of this function is optional. The devfs_register() function
+ * will automatically create intermediate directories as needed. This function
+ * is provided for efficiency reasons, as it provides a handle to a directory.
+ * Returns a handle which may later be used in a call to devfs_unregister().
+ * On failure %NULL is returned.
+ */
+
devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name,
unsigned int namelen, void *info)
-/* [SUMMARY] Create a directory in the devfs namespace.
- <dir> The handle to the parent devfs directory entry. If this is NULL the
- new name is relative to the root of the devfs.
- <name> The name of the entry.
- <namelen> The number of characters in <<name>>, not including a NULL
- terminator. If this is 0, then <<name>> must be NULL-terminated and the
- length is computed internally.
- <info> An arbitrary pointer which will be associated with the entry.
- [NOTE] Use of this function is optional. The [<devfs_register>] function
- will automatically create intermediate directories as needed. This function
- is provided for efficiency reasons, as it provides a handle to a directory.
- [RETURNS] A handle which may later be used in a call to
- [<devfs_unregister>]. On failure NULL is returned.
-*/
{
int is_new;
struct devfs_entry *de;
@@ -1499,29 +1552,31 @@ devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name,
return de;
} /* End Function devfs_mk_dir */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_find_handle - Find the handle of a devfs entry.
+ * @dir: The handle to the parent devfs directory entry. If this is %NULL the
+ * name is relative to the root of the devfs.
+ * @name: The name of the entry.
+ * @namelen: The number of characters in @name, not including a %NULL
+ * terminator. If this is 0, then @name must be %NULL-terminated and the
+ * length is computed internally.
+ * @major: The major number. This is used if @name is %NULL.
+ * @minor: The minor number. This is used if @name is %NULL.
+ * @type: The type of special file to search for. This may be either
+ * %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
+ * @traverse_symlinks: If %TRUE then symlink entries in the devfs namespace are
+ * traversed. Symlinks pointing out of the devfs namespace will cause a
+ * failure. Symlink traversal consumes stack space.
+ *
+ * Returns a handle which may later be used in a call to devfs_unregister(),
+ * devfs_get_flags(), or devfs_set_flags(). On failure %NULL is returned.
+ */
+
devfs_handle_t devfs_find_handle (devfs_handle_t dir,
const char *name, unsigned int namelen,
unsigned int major, unsigned int minor,
char type, int traverse_symlinks)
-/* [SUMMARY] Find the handle of a devfs entry.
- <dir> The handle to the parent devfs directory entry. If this is NULL the
- name is relative to the root of the devfs.
- <name> The name of the entry.
- <namelen> The number of characters in <<name>>, not including a NULL
- terminator. If this is 0, then <<name>> must be NULL-terminated and the
- length is computed internally.
- <major> The major number. This is used if <<name>> is NULL.
- <minor> The minor number. This is used if <<name>> is NULL.
- <type> The type of special file to search for. This may be either
- DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK.
- <traverse_symlinks> If TRUE then symlink entries in the devfs namespace are
- traversed. Symlinks pointing out of the devfs namespace will cause a
- failure. Symlink traversal consumes stack space.
- [RETURNS] A handle which may later be used in a call to
- [<devfs_unregister>], [<devfs_get_flags>], or [<devfs_set_flags>].
- On failure NULL is returned.
-*/
{
devfs_handle_t de;
@@ -1533,13 +1588,16 @@ devfs_handle_t devfs_find_handle (devfs_handle_t dir,
return de;
} /* End Function devfs_find_handle */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_flags - Get the flags for a devfs entry.
+ * @de: The handle to the device entry.
+ * @flags: The flags are written here.
+ *
+ * Returns 0 on success, else a negative error code.
+ */
+
int devfs_get_flags (devfs_handle_t de, unsigned int *flags)
-/* [SUMMARY] Get the flags for a devfs entry.
- <de> The handle to the device entry.
- <flags> The flags are written here.
- [RETURNS] 0 on success, else a negative error code.
-*/
{
unsigned int fl = 0;
@@ -1557,13 +1615,16 @@ int devfs_get_flags (devfs_handle_t de, unsigned int *flags)
return 0;
} /* End Function devfs_get_flags */
-/*PUBLIC_FUNCTION*/
+
+/*
+ * devfs_set_flags - Set the flags for a devfs entry.
+ * @de: The handle to the device entry.
+ * @flags: The flags to set. Unset flags are cleared.
+ *
+ * Returns 0 on success, else a negative error code.
+ */
+
int devfs_set_flags (devfs_handle_t de, unsigned int flags)
-/* [SUMMARY] Set the flags for a devfs entry.
- <de> The handle to the device entry.
- <flags> The flags to set. Unset flags are cleared.
- [RETURNS] 0 on success, else a negative error code.
-*/
{
if (de == NULL) return -EINVAL;
if (!de->registered) return -ENODEV;
@@ -1592,15 +1653,18 @@ int devfs_set_flags (devfs_handle_t de, unsigned int flags)
return 0;
} /* End Function devfs_set_flags */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_maj_min - Get the major and minor numbers for a devfs entry.
+ * @de: The handle to the device entry.
+ * @major: The major number is written here. This may be %NULL.
+ * @minor: The minor number is written here. This may be %NULL.
+ *
+ * Returns 0 on success, else a negative error code.
+ */
+
int devfs_get_maj_min (devfs_handle_t de, unsigned int *major,
unsigned int *minor)
-/* [SUMMARY] Get the major and minor numbers for a devfs entry.
- <de> The handle to the device entry.
- <major> The major number is written here. This may be NULL.
- <minor> The minor number is written here. This may be NULL.
- [RETURNS] 0 on success, else a negative error code.
-*/
{
if (de == NULL) return -EINVAL;
if (!de->registered) return -ENODEV;
@@ -1611,12 +1675,15 @@ int devfs_get_maj_min (devfs_handle_t de, unsigned int *major,
return 0;
} /* End Function devfs_get_maj_min */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_handle_from_inode - Get the devfs handle for a VFS inode.
+ * @inode: The VFS inode.
+ *
+ * Returns the devfs handle on success, else %NULL.
+ */
+
devfs_handle_t devfs_get_handle_from_inode (struct inode *inode)
-/* [SUMMARY] Get the devfs handle for a VFS inode.
- <inode> The VFS inode.
- [RETURNS] The devfs handle on success, else NULL.
-*/
{
struct devfs_inode *di;
@@ -1627,16 +1694,19 @@ devfs_handle_t devfs_get_handle_from_inode (struct inode *inode)
return di->de;
} /* End Function devfs_get_handle_from_inode */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_generate_path - Generate a pathname for an entry, relative to the devfs root.
+ * @de: The devfs entry.
+ * @path: The buffer to write the pathname to. The pathname and '\0'
+ * terminator will be written at the end of the buffer.
+ * @buflen: The length of the buffer.
+ *
+ * Returns the offset in the buffer where the pathname starts on success,
+ * else a negative error code.
+ */
+
int devfs_generate_path (devfs_handle_t de, char *path, int buflen)
-/* [SUMMARY] Generate a pathname for an entry, relative to the devfs root.
- <de> The devfs entry.
- <path> The buffer to write the pathname to. The pathname and '\0'
- terminator will be written at the end of the buffer.
- <buflen> The length of the buffer.
- [RETURNS] The offset in the buffer where the pathname starts on success,
- else a negative error code.
-*/
{
int pos;
@@ -1656,12 +1726,15 @@ int devfs_generate_path (devfs_handle_t de, char *path, int buflen)
return pos;
} /* End Function devfs_generate_path */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_ops - Get the device operations for a devfs entry.
+ * @de: The handle to the device entry.
+ *
+ * Returns a pointer to the device operations on success, else NULL.
+ */
+
void *devfs_get_ops (devfs_handle_t de)
-/* [SUMMARY] Get the device operations for a devfs entry.
- <de> The handle to the device entry.
- [RETURNS] A pointer to the device operations on success, else NULL.
-*/
{
if (de == NULL) return NULL;
if (!de->registered) return NULL;
@@ -1670,13 +1743,16 @@ void *devfs_get_ops (devfs_handle_t de)
return NULL;
} /* End Function devfs_get_ops */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_set_file_size - Set the file size for a devfs regular file.
+ * de: The handle to the device entry.
+ * size: The new file size.
+ *
+ * Returns 0 on success, else a negative error code.
+ */
+
int devfs_set_file_size (devfs_handle_t de, unsigned long size)
-/* [SUMMARY] Set the file size for a devfs regular file.
- <de> The handle to the device entry.
- <size> The new file size.
- [RETURNS] 0 on success, else a negative error code.
-*/
{
struct devfs_inode *di;
@@ -1694,24 +1770,28 @@ int devfs_set_file_size (devfs_handle_t de, unsigned long size)
return 0;
} /* End Function devfs_set_file_size */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_info - Get the info pointer written to private_data of @de upon open.
+ * @de: The handle to the device entry.
+ *
+ * Returns the info pointer.
+ */
void *devfs_get_info (devfs_handle_t de)
-/* [SUMMARY] Get the info pointer written to <<private_data>> upon open.
- <de> The handle to the device entry.
- [RETURNS] The info pointer.
-*/
{
if (de == NULL) return NULL;
if (!de->registered) return NULL;
return de->info;
} /* End Function devfs_get_info */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_set_info - Set the info pointer written to private_data upon open.
+ * @de: The handle to the device entry.
+ *
+ * Returns 0 on success, else a negative error code.
+ */
int devfs_set_info (devfs_handle_t de, void *info)
-/* [SUMMARY] Set the info pointer written to <<private_data>> upon open.
- <de> The handle to the device entry.
- [RETURNS] 0 on success, else a negative error code.
-*/
{
if (de == NULL) return -EINVAL;
if (!de->registered) return -EINVAL;
@@ -1719,24 +1799,29 @@ int devfs_set_info (devfs_handle_t de, void *info)
return 0;
} /* End Function devfs_set_info */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_parent - Get the parent device entry.
+ * @de: The handle to the device entry.
+ *
+ * Returns the parent device entry if it exists, else %NULL.
+ */
devfs_handle_t devfs_get_parent (devfs_handle_t de)
-/* [SUMMARY] Get the parent device entry.
- <de> The handle to the device entry.
- [RETURNS] The parent device entry if it exists, else NULL.
-*/
{
if (de == NULL) return NULL;
if (!de->registered) return NULL;
return de->parent;
} /* End Function devfs_get_parent */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_first_child - Get the first leaf node in a directory.
+ * @de: The handle to the device entry.
+ *
+ * Returns the leaf node device entry if it exists, else %NULL.
+ */
+
devfs_handle_t devfs_get_first_child (devfs_handle_t de)
-/* [SUMMARY] Get the first leaf node in a directory.
- <de> The handle to the device entry.
- [RETURNS] The leaf node device entry if it exists, else NULL.
-*/
{
if (de == NULL) return NULL;
if (!de->registered) return NULL;
@@ -1744,27 +1829,31 @@ devfs_handle_t devfs_get_first_child (devfs_handle_t de)
return de->u.dir.first;
} /* End Function devfs_get_first_child */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_next_sibling - Get the next sibling leaf node. for a device entry.
+ * @de: The handle to the device entry.
+ *
+ * Returns the leaf node device entry if it exists, else %NULL.
+ */
+
devfs_handle_t devfs_get_next_sibling (devfs_handle_t de)
-/* [SUMMARY] Get the next sibling leaf node. for a device entry.
- <de> The handle to the device entry.
- [RETURNS] The leaf node device entry if it exists, else NULL.
-*/
{
if (de == NULL) return NULL;
if (!de->registered) return NULL;
return de->next;
} /* End Function devfs_get_next_sibling */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_auto_unregister - Configure a devfs entry to be automatically unregistered.
+ * @master: The master devfs entry. Only one slave may be registered.
+ * @slave: The devfs entry which will be automatically unregistered when the
+ * master entry is unregistered. It is illegal to call devfs_unregister()
+ * on this entry.
+ */
+
void devfs_auto_unregister (devfs_handle_t master, devfs_handle_t slave)
-/* [SUMMARY] Configure a devfs entry to be automatically unregistered.
- <master> The master devfs entry. Only one slave may be registered.
- <slave> The devfs entry which will be automatically unregistered when the
- master entry is unregistered. It is illegal to call [<devfs_unregister>] on
- this entry.
- [RETURNS] Nothing.
-*/
{
if (master == NULL) return;
if (master->slave != NULL)
@@ -1779,25 +1868,30 @@ void devfs_auto_unregister (devfs_handle_t master, devfs_handle_t slave)
master->slave = slave;
} /* End Function devfs_auto_unregister */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_unregister_slave - Get the slave entry which will be automatically unregistered.
+ * @master: The master devfs entry.
+ *
+ * Returns the slave which will be unregistered when @master is unregistered.
+ */
+
devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master)
-/* [SUMMARY] Get the slave entry which will be automatically unregistered.
- <master> The master devfs entry.
- [RETURNS] The slave which will be unregistered when <<master>> is
- unregistered.
-*/
{
if (master == NULL) return NULL;
return master->slave;
} /* End Function devfs_get_unregister_slave */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_get_name - Get the name for a device entry in its parent directory.
+ * @de: The handle to the device entry.
+ * @namelen: The length of the name is written here. This may be %NULL.
+ *
+ * Returns the name on success, else %NULL.
+ */
+
const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen)
-/* [SUMMARY] Get the name for a device entry in its parent directory.
- <de> The handle to the device entry.
- <namelen> The length of the name is written here. This may be NULL.
- [RETURNS] The name on success, else NULL.
-*/
{
if (de == NULL) return NULL;
if (!de->registered) return NULL;
@@ -1805,61 +1899,73 @@ const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen)
return de->name;
} /* End Function devfs_get_name */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_register_chrdev - Optionally register a conventional character driver.
+ * @major: The major number for the driver.
+ * @name: The name of the driver (as seen in /proc/devices).
+ * @fops: The &file_operations structure pointer.
+ *
+ * This function will register a character driver provided the "devfs=only"
+ * option was not provided at boot time.
+ * Returns 0 on success, else a negative error code on failure.
+ */
+
int devfs_register_chrdev (unsigned int major, const char *name,
struct file_operations *fops)
-/* [SUMMARY] Optionally register a conventional character driver.
- [PURPOSE] This function will register a character driver provided the
- "devfs=only" option was not provided at boot time.
- <major> The major number for the driver.
- <name> The name of the driver (as seen in /proc/devices).
- <fops> The file_operations structure pointer.
- [RETURNS] 0 on success, else a negative error code on failure.
-*/
{
if (boot_options & OPTION_ONLY) return 0;
return register_chrdev (major, name, fops);
} /* End Function devfs_register_chrdev */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_register_blkdev - Optionally register a conventional block driver.
+ * @major: The major number for the driver.
+ * @name: The name of the driver (as seen in /proc/devices).
+ * @bdops: The &block_device_operations structure pointer.
+ *
+ * This function will register a block driver provided the "devfs=only"
+ * option was not provided at boot time.
+ * Returns 0 on success, else a negative error code on failure.
+ */
+
int devfs_register_blkdev (unsigned int major, const char *name,
struct block_device_operations *bdops)
-/* [SUMMARY] Optionally register a conventional block driver.
- [PURPOSE] This function will register a block driver provided the
- "devfs=only" option was not provided at boot time.
- <major> The major number for the driver.
- <name> The name of the driver (as seen in /proc/devices).
- <bdops> The block_device_operations structure pointer.
- [RETURNS] 0 on success, else a negative error code on failure.
-*/
{
if (boot_options & OPTION_ONLY) return 0;
return register_blkdev (major, name, bdops);
} /* End Function devfs_register_blkdev */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_unregister_chrdev - Optionally unregister a conventional character driver.
+ * major: The major number for the driver.
+ * name: The name of the driver (as seen in /proc/devices).
+ *
+ * This function will unregister a character driver provided the "devfs=only"
+ * option was not provided at boot time.
+ * Returns 0 on success, else a negative error code on failure.
+ */
+
int devfs_unregister_chrdev (unsigned int major, const char *name)
-/* [SUMMARY] Optionally unregister a conventional character driver.
- [PURPOSE] This function will unregister a character driver provided the
- "devfs=only" option was not provided at boot time.
- <major> The major number for the driver.
- <name> The name of the driver (as seen in /proc/devices).
- [RETURNS] 0 on success, else a negative error code on failure.
-*/
{
if (boot_options & OPTION_ONLY) return 0;
return unregister_chrdev (major, name);
} /* End Function devfs_unregister_chrdev */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_unregister_blkdev - Optionally unregister a conventional block driver.
+ * @major: The major number for the driver.
+ * @name: The name of the driver (as seen in /proc/devices).
+ *
+ * This function will unregister a block driver provided the "devfs=only"
+ * option was not provided at boot time.
+ * Returns 0 on success, else a negative error code on failure.
+ */
+
int devfs_unregister_blkdev (unsigned int major, const char *name)
-/* [SUMMARY] Optionally unregister a conventional block driver.
- [PURPOSE] This function will unregister a block driver provided the
- "devfs=only" option was not provided at boot time.
- <major> The major number for the driver.
- <name> The name of the driver (as seen in /proc/devices).
- [RETURNS] 0 on success, else a negative error code on failure.
-*/
{
if (boot_options & OPTION_ONLY) return 0;
return unregister_blkdev (major, name);
@@ -1867,13 +1973,13 @@ int devfs_unregister_blkdev (unsigned int major, const char *name)
#ifndef MODULE
-/*UNPUBLISHED_FUNCTION*/
+/**
+ * devfs_setup - Process kernel boot options.
+ * @str: The boot options after the "devfs=".
+ * @unused: Unused.
+ */
+
SETUP_STATIC int __init devfs_setup (char *str)
-/* [SUMMARY] Process kernel boot options.
- <str> The boot options after the "devfs=".
- <unused> Unused.
- [RETURNS] Nothing.
-*/
{
while ( (*str != '\0') && !isspace (*str) )
{
@@ -2027,13 +2133,17 @@ static void update_devfs_inode_from_entry (struct devfs_inode *di)
}
} /* End Function update_devfs_inode_from_entry */
+
+/**
+ * create_devfs_inode - Create a devfs inode entry.
+ * @de: The devfs entry to associate the new inode with.
+ * @fs_info: The FS info.
+ *
+ * Returns a pointer to the devfs inode on success, else %NULL.
+ */
+
static struct devfs_inode *create_devfs_inode (struct devfs_entry *de,
struct fs_info *fs_info)
-/* [SUMMARY] Create a devfs inode entry.
- <de> The devfs entry to associate the new inode with.
- <fs_info> The FS info.
- [RETURNS] A pointer to the devfs inode on success, else NULL.
-*/
{
struct devfs_inode *di, **table;
@@ -2077,18 +2187,22 @@ static struct devfs_inode *create_devfs_inode (struct devfs_entry *de,
return di;
} /* End Function create_devfs_inode */
+
+/**
+ * try_modload - Notify devfsd of an inode lookup.
+ * @parent: The parent devfs entry.
+ * @fs_info: The filesystem info.
+ * @name: The device name.
+ * @namelen: The number of characters in @name.
+ * @buf: A working area that will be used. This must not go out of scope until
+ * devfsd is idle again.
+ *
+ * Returns 0 on success, else a negative error code.
+ */
+
static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
const char *name, unsigned namelen,
char buf[STRING_LENGTH])
-/* [SUMMARY] Notify devfsd of an inode lookup.
- <parent> The parent devfs entry.
- <fs_info> The filesystem info.
- <name> The device name.
- <namelen> The number of characters in <<name>>.
- <buf> A working area that will be used. This must not go out of scope until
- devfsd is idle again.
- [RETURNS] 0 on success, else a negative error code.
-*/
{
int pos;
@@ -2136,11 +2250,15 @@ static void delete_fs (struct fs_info *fs_info)
kfree (fs_info);
} /* End Function delete_fs */
+
+/**
+ * check_disc_changed - Check if a removable disc was changed.
+ * @de: The device.
+ *
+ * Returns 1 if the media was changed, else 0.
+ */
+
static int check_disc_changed (struct devfs_entry *de)
-/* [SUMMARY] Check if a removable disc was changed.
- <de> The device.
- [RETURNS] 1 if the media was changed, else 0.
-*/
{
int tmp;
kdev_t dev = MKDEV (de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
@@ -2166,11 +2284,13 @@ static int check_disc_changed (struct devfs_entry *de)
return 1;
} /* End Function check_disc_changed */
+
+/**
+ * scan_dir_for_removable - Scan a directory for removable media devices and check media.
+ * @dir: The directory.
+ */
+
static void scan_dir_for_removable (struct devfs_entry *dir)
-/* [SUMMARY] Scan a directory for removable media devices and check media.
- <dir> The directory.
- [RETURNS] Nothing.
-*/
{
struct devfs_entry *de;
@@ -2184,14 +2304,17 @@ static void scan_dir_for_removable (struct devfs_entry *dir)
}
} /* End Function scan_dir_for_removable */
+/**
+ * get_removable_partition - Get removable media partition.
+ * @dir: The parent directory.
+ * @name: The name of the entry.
+ * @namelen: The number of characters in <<name>>.
+ *
+ * Returns 1 if the media was changed, else 0.
+ */
+
static int get_removable_partition (struct devfs_entry *dir, const char *name,
unsigned int namelen)
-/* [SUMMARY] Get removable media partition.
- <dir> The parent directory.
- <name> The name of the entry.
- <namelen> The number of characters in <<name>>.
- [RETURNS] 1 if the media was changed, else 0.
-*/
{
struct devfs_entry *de;
@@ -2365,15 +2488,19 @@ static struct super_operations devfs_sops =
statfs: devfs_statfs,
};
+
+/**
+ * get_vfs_inode - Get a VFS inode.
+ * @sb: The super block.
+ * @di: The devfs inode.
+ * @dentry The dentry to register with the devfs inode.
+ *
+ * Returns the inode on success, else %NULL.
+ */
+
static struct inode *get_vfs_inode (struct super_block *sb,
struct devfs_inode *di,
struct dentry *dentry)
-/* [SUMMARY] Get a VFS inode.
- <sb> The super block.
- <di> The devfs inode.
- <dentry> The dentry to register with the devfs inode.
- [RETURNS] The inode on success, else NULL.
-*/
{
struct inode *inode;
@@ -2551,9 +2678,13 @@ static struct file_operations devfs_fops =
/* Dentry operations for device entries follow */
+
+/**
+ * devfs_d_release - Callback for when a dentry is freed.
+ * @dentry: The dentry.
+ */
+
static void devfs_d_release (struct dentry *dentry)
-/* [SUMMARY] Callback for when a dentry is freed.
-*/
{
#ifdef CONFIG_DEVFS_DEBUG
struct inode *inode = dentry->d_inode;
@@ -2564,9 +2695,13 @@ static void devfs_d_release (struct dentry *dentry)
#endif
} /* End Function devfs_d_release */
+/**
+ * devfs_d_iput - Callback for when a dentry loses its inode.
+ * @dentry: The dentry.
+ * @inode: The inode.
+ */
+
static void devfs_d_iput (struct dentry *dentry, struct inode *inode)
-/* [SUMMARY] Callback for when a dentry loses its inode.
-*/
{
struct devfs_inode *di;
@@ -2587,7 +2722,7 @@ static void devfs_d_iput (struct dentry *dentry, struct inode *inode)
iput (inode);
} /* End Function devfs_d_iput */
-static void devfs_d_delete (struct dentry *dentry);
+static int devfs_d_delete (struct dentry *dentry);
static struct dentry_operations devfs_dops =
{
@@ -2606,9 +2741,12 @@ static struct dentry_operations devfs_wait_dops =
d_revalidate: devfs_d_revalidate_wait,
};
-static void devfs_d_delete (struct dentry *dentry)
-/* [SUMMARY] Callback for when all files for a dentry are closed.
-*/
+/**
+ * devfs_d_delete - Callback for when all files for a dentry are closed.
+ * @detry: The dentry.
+ */
+
+static int devfs_d_delete (struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct devfs_inode *di;
@@ -2623,8 +2761,7 @@ static void devfs_d_delete (struct dentry *dentry)
printk ("%s: d_delete(): dropping negative dentry: %p\n",
DEVFS_NAME, dentry);
#endif
- d_drop (dentry);
- return;
+ return 1;
}
fs_info = inode->i_sb->u.generic_sbp;
di = get_devfs_inode_from_vfs_inode (inode);
@@ -2633,16 +2770,16 @@ static void devfs_d_delete (struct dentry *dentry)
printk ("%s: d_delete(): dentry: %p inode: %p devfs_inode: %p\n",
DEVFS_NAME, dentry, inode, di);
#endif
- if (di == NULL) return;
- if (di->de == NULL) return;
+ if (di == NULL) return 0;
+ if (di->de == NULL) return 0;
if ( !S_ISCHR (di->mode) && !S_ISBLK (di->mode) && !S_ISREG (di->mode) )
- return;
- if (!di->de->u.fcb.open) return;
+ return 0;
+ if (!di->de->u.fcb.open) return 0;
di->de->u.fcb.open = FALSE;
if (di->de->u.fcb.aopen_notify)
devfsd_notify_one (di->de, DEVFSD_NOTIFY_CLOSE, inode->i_mode,
current->euid, current->egid, fs_info);
- if (!di->de->u.fcb.auto_owner) return;
+ if (!di->de->u.fcb.auto_owner) return 0;
/* Change the ownership/protection back */
di->mode = (di->mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO;
di->uid = di->de->u.fcb.default_uid;
@@ -2650,6 +2787,7 @@ static void devfs_d_delete (struct dentry *dentry)
inode->i_mode = di->mode;
inode->i_uid = di->uid;
inode->i_gid = di->gid;
+ return 0;
} /* End Function devfs_d_delete */
static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
@@ -3431,11 +3569,9 @@ int __init init_devfs_fs (void)
void __init mount_devfs_fs (void)
{
int err;
- extern long do_sys_mount (char *dev_name, char *dir_name,
- char *type, int flags, void *data);
if ( (boot_options & OPTION_NOMOUNT) ) return;
- err = do_sys_mount ("none", "/dev", "devfs", 0, "");
+ err = do_mount ("none", "/dev", "devfs", 0, "");
if (err == 0) printk ("Mounted devfs on /dev\n");
else printk ("Warning: unable to mount devfs, err: %d\n", err);
} /* End Function mount_devfs_fs */
diff --git a/fs/devfs/util.c b/fs/devfs/util.c
index 7e22ae7cb..fe4746448 100644
--- a/fs/devfs/util.c
+++ b/fs/devfs/util.c
@@ -38,13 +38,14 @@
/* Private functions follow */
+/**
+ * _devfs_convert_name - Convert from an old style location-based name to new style.
+ * @new: The new name will be written here.
+ * @old: The old name.
+ * @disc: If true, disc partitioning information should be processed.
+ */
+
static void __init _devfs_convert_name (char *new, const char *old, int disc)
-/* [SUMMARY] Convert from an old style location-based name to new style.
- <new> The new name will be written here.
- <old> The old name.
- <disc> If true, disc partitioning information should be processed.
- [RETURNS] Nothing.
-*/
{
int host, bus, target, lun;
char *ptr;
@@ -73,12 +74,12 @@ static void __init _devfs_convert_name (char *new, const char *old, int disc)
/* Public functions follow */
-/*PUBLIC_FUNCTION*/
+/**
+ * devfs_make_root - Create the root FS device entry if required.
+ * @name: The name of the root FS device, as passed by "root=".
+ */
+
void __init devfs_make_root (const char *name)
-/* [SUMMARY] Create the root FS device entry if required.
- <name> The name of the root FS device, as passed by "root=".
- [RETURNS] Nothing.
-*/
{
char dest[64];
@@ -97,12 +98,13 @@ void __init devfs_make_root (const char *name)
devfs_mk_symlink (NULL, name, 0, DEVFS_FL_DEFAULT, dest, 0, NULL,NULL);
} /* End Function devfs_make_root */
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_register_tape - Register a tape device in the "/dev/tapes" hierarchy.
+ * @de: Any tape device entry in the device directory.
+ */
+
void devfs_register_tape (devfs_handle_t de)
-/* [SUMMARY] Register a tape device in the "/dev/tapes" hierarchy.
- <de> Any tape device entry in the device directory.
- [RETURNS] Nothing.
-*/
{
int pos;
devfs_handle_t parent, slave;
@@ -122,30 +124,31 @@ void devfs_register_tape (devfs_handle_t de)
} /* End Function devfs_register_tape */
EXPORT_SYMBOL(devfs_register_tape);
-/*PUBLIC_FUNCTION*/
+
+/**
+ * devfs_register_series - Register a sequence of device entries.
+ * @dir: The handle to the parent devfs directory entry. If this is %NULL the
+ * new names are relative to the root of the devfs.
+ * @format: The printf-style format string. A single "\%u" is allowed.
+ * @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
+ * @major: The major number. Not needed for regular files.
+ * @minor_start: The starting minor number. Not needed for regular files.
+ * @mode: The default file mode.
+ * @uid: The default UID of the file.
+ * @guid: The default GID of the file.
+ * @ops: The &file_operations or &block_device_operations structure.
+ * This must not be externally deallocated.
+ * @info: An arbitrary pointer which will be written to the private_data
+ * field of the &file structure passed to the device driver. You can set
+ * this to whatever you like, and change it once the file is opened (the next
+ * file opened will not see this change).
+ */
+
void devfs_register_series (devfs_handle_t dir, const char *format,
unsigned int num_entries, unsigned int flags,
unsigned int major, unsigned int minor_start,
umode_t mode, uid_t uid, gid_t gid,
void *ops, void *info)
-/* [SUMMARY] Register a sequence of device entries.
- <dir> The handle to the parent devfs directory entry. If this is NULL the
- new names are relative to the root of the devfs.
- <format> The printf-style format string. A single "%u" is allowed.
- <flags> A set of bitwise-ORed flags (DEVFS_FL_*).
- <major> The major number. Not needed for regular files.
- <minor_start> The starting minor number. Not needed for regular files.
- <mode> The default file mode.
- <uid> The default UID of the file.
- <guid> The default GID of the file.
- <ops> The <<file_operations>> or <<block_device_operations>> structure.
- This must not be externally deallocated.
- <info> An arbitrary pointer which will be written to the <<private_data>>
- field of the <<file>> structure passed to the device driver. You can set
- this to whatever you like, and change it once the file is opened (the next
- file opened will not see this change).
- [RETURNS] Nothing.
-*/
{
unsigned int count;
char devname[128];
diff --git a/fs/exec.c b/fs/exec.c
index 992bbd6aa..681139843 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -45,8 +45,8 @@
#include <linux/kmod.h>
#endif
-static struct linux_binfmt *formats = (struct linux_binfmt *) NULL;
-static spinlock_t binfmt_lock = SPIN_LOCK_UNLOCKED;
+static struct linux_binfmt *formats;
+static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED;
int register_binfmt(struct linux_binfmt * fmt)
{
@@ -56,17 +56,17 @@ int register_binfmt(struct linux_binfmt * fmt)
return -EINVAL;
if (fmt->next)
return -EBUSY;
- spin_lock(&binfmt_lock);
+ write_lock(&binfmt_lock);
while (*tmp) {
if (fmt == *tmp) {
- spin_unlock(&binfmt_lock);
+ write_unlock(&binfmt_lock);
return -EBUSY;
}
tmp = &(*tmp)->next;
}
fmt->next = formats;
formats = fmt;
- spin_unlock(&binfmt_lock);
+ write_unlock(&binfmt_lock);
return 0;
}
@@ -74,16 +74,16 @@ int unregister_binfmt(struct linux_binfmt * fmt)
{
struct linux_binfmt ** tmp = &formats;
- spin_lock(&binfmt_lock);
+ write_lock(&binfmt_lock);
while (*tmp) {
if (fmt == *tmp) {
*tmp = fmt->next;
- spin_unlock(&binfmt_lock);
+ write_unlock(&binfmt_lock);
return 0;
}
tmp = &(*tmp)->next;
}
- spin_unlock(&binfmt_lock);
+ write_unlock(&binfmt_lock);
return -EINVAL;
}
@@ -103,35 +103,34 @@ asmlinkage long sys_uselib(const char * library)
{
int fd, retval;
struct file * file;
- struct linux_binfmt * fmt;
- lock_kernel();
fd = sys_open(library, 0, 0);
- retval = fd;
if (fd < 0)
- goto out;
+ return fd;
file = fget(fd);
retval = -ENOEXEC;
- if (file && file->f_op && file->f_op->read) {
- spin_lock(&binfmt_lock);
- for (fmt = formats ; fmt ; fmt = fmt->next) {
- if (!fmt->load_shlib)
- continue;
- if (!try_inc_mod_count(fmt->module))
- continue;
- spin_unlock(&binfmt_lock);
- retval = fmt->load_shlib(file);
- spin_lock(&binfmt_lock);
- put_binfmt(fmt);
- if (retval != -ENOEXEC)
- break;
+ if (file) {
+ if(file->f_op && file->f_op->read) {
+ struct linux_binfmt * fmt;
+
+ read_lock(&binfmt_lock);
+ for (fmt = formats ; fmt ; fmt = fmt->next) {
+ if (!fmt->load_shlib)
+ continue;
+ if (!try_inc_mod_count(fmt->module))
+ continue;
+ read_unlock(&binfmt_lock);
+ retval = fmt->load_shlib(file);
+ read_lock(&binfmt_lock);
+ put_binfmt(fmt);
+ if (retval != -ENOEXEC)
+ break;
+ }
+ read_unlock(&binfmt_lock);
}
- spin_unlock(&binfmt_lock);
+ fput(file);
}
- fput(file);
sys_close(fd);
-out:
- unlock_kernel();
return retval;
}
@@ -288,6 +287,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
if (!mpnt)
return -ENOMEM;
+ down(&current->mm->mmap_sem);
{
mpnt->vm_mm = current->mm;
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
@@ -311,6 +311,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
}
stack_base += PAGE_SIZE;
}
+ up(&current->mm->mmap_sem);
return 0;
}
@@ -745,14 +746,14 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
}
#endif
for (try=0; try<2; try++) {
- spin_lock(&binfmt_lock);
+ read_lock(&binfmt_lock);
for (fmt = formats ; fmt ; fmt = fmt->next) {
int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
if (!fn)
continue;
if (!try_inc_mod_count(fmt->module))
continue;
- spin_unlock(&binfmt_lock);
+ read_unlock(&binfmt_lock);
retval = fn(bprm, regs);
if (retval >= 0) {
put_binfmt(fmt);
@@ -762,16 +763,16 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
current->did_exec = 1;
return retval;
}
- spin_lock(&binfmt_lock);
+ read_lock(&binfmt_lock);
put_binfmt(fmt);
if (retval != -ENOEXEC)
break;
if (!bprm->file) {
- spin_unlock(&binfmt_lock);
+ read_unlock(&binfmt_lock);
return retval;
}
}
- spin_unlock(&binfmt_lock);
+ read_unlock(&binfmt_lock);
if (retval != -ENOEXEC) {
break;
#ifdef CONFIG_KMOD
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 90ce121ce..a3f8ae4ce 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -209,7 +209,7 @@ static inline int load_block_bitmap (struct super_block * sb,
*/
if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
sb->u.ext2_sb.s_block_bitmap_number[0] == block_group &&
- sb->u.ext2_sb.s_block_bitmap[block_group]) {
+ sb->u.ext2_sb.s_block_bitmap[0]) {
return 0;
}
/*
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index dff1b6841..3e471f42b 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -577,7 +577,6 @@ static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
- d_delete(dentry);
end_rmdir:
brelse (bh);
@@ -619,7 +618,6 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry)
mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime;
retval = 0;
- d_delete(dentry); /* This also frees the inode */
end_unlink:
brelse (bh);
diff --git a/fs/hfs/balloc.c b/fs/hfs/balloc.c
index d7e17e72f..4edd6b748 100644
--- a/fs/hfs/balloc.c
+++ b/fs/hfs/balloc.c
@@ -86,6 +86,8 @@ static struct hfs_bnode_ref hfs_bnode_init(struct hfs_btree * tree,
retval.bn->magic = HFS_BNODE_MAGIC;
retval.bn->tree = tree;
retval.bn->node = node;
+ hfs_init_waitqueue(&retval.bn->wqueue);
+ hfs_init_waitqueue(&retval.bn->rqueue);
hfs_bnode_lock(&retval, HFS_LOCK_WRITE);
retval.bn->buf = get_new_node(tree, node);
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index 85e3a909b..e2b975fae 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -60,7 +60,7 @@ typedef struct {
hfs_byte_t RExtRec[12]; /* first extent record
for the resource fork */
hfs_lword_t Resrv; /* reserved by Apple */
-} FIL_REC;
+} __attribute__((packed)) FIL_REC;
/* the catalog record for a directory */
typedef struct {
@@ -74,14 +74,14 @@ typedef struct {
hfs_dinfo_t UsrInfo; /* data used by the Finder */
hfs_dxinfo_t FndrInfo; /* more data used by Finder */
hfs_byte_t Resrv[16]; /* reserved by Apple */
-} DIR_REC;
+} __attribute__((packed)) DIR_REC;
/* the catalog record for a thread */
typedef struct {
hfs_byte_t Reserv[8]; /* reserved by Apple */
hfs_lword_t ParID; /* CNID of parent directory */
struct hfs_name CName; /* The name of this entry */
-} THD_REC;
+} __attribute__((packed)) THD_REC;
/* A catalog tree record */
struct hfs_cat_rec {
@@ -92,7 +92,7 @@ struct hfs_cat_rec {
DIR_REC dir;
THD_REC thd;
} u;
-};
+} __attribute__((packed));
/*================ File-local variables ================*/
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 07f4ab93d..d6de087e9 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -274,7 +274,6 @@ int hfs_unlink(struct inode * dir, struct dentry *dentry)
inode->i_nlink--;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
- d_delete(dentry);
update_dirs_minus(entry, 0);
}
@@ -328,7 +327,6 @@ int hfs_rmdir(struct inode * parent, struct dentry *dentry)
inode->i_nlink = 0;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
- d_delete(dentry);
update_dirs_minus(entry, 1);
hfs_rmdir_put:
diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c
index 80e47fc62..ba62615b0 100644
--- a/fs/hfs/file_hdr.c
+++ b/fs/hfs/file_hdr.c
@@ -158,7 +158,7 @@ struct hdr_hdr {
hfs_byte_t filler[16];
hfs_word_t entries;
hfs_byte_t descrs[12*HFS_HDR_MAX];
-};
+} __attribute__((packed));
/*================ File-local functions ================*/
diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h
index 3819a685f..9552bbb34 100644
--- a/fs/hfs/hfs.h
+++ b/fs/hfs/hfs.h
@@ -130,7 +130,7 @@
struct hfs_name {
hfs_byte_t Len;
hfs_byte_t Name[31];
-};
+} __attribute__((packed));
typedef struct {
hfs_word_t v;
@@ -150,21 +150,21 @@ typedef struct {
hfs_word_t fdFlags;
hfs_point_t fdLocation;
hfs_word_t fdFldr;
-} hfs_finfo_t;
+} __attribute__((packed)) hfs_finfo_t;
typedef struct {
hfs_word_t fdIconID;
hfs_byte_t fdUnused[8];
hfs_word_t fdComment;
hfs_lword_t fdPutAway;
-} hfs_fxinfo_t;
+} __attribute__((packed)) hfs_fxinfo_t;
typedef struct {
hfs_rect_t frRect;
hfs_word_t frFlags;
hfs_point_t frLocation;
hfs_word_t frView;
-} hfs_dinfo_t;
+} __attribute__((packed)) hfs_dinfo_t;
typedef struct {
hfs_point_t frScroll;
@@ -172,7 +172,7 @@ typedef struct {
hfs_word_t frUnused;
hfs_word_t frComment;
hfs_lword_t frPutAway;
-} hfs_dxinfo_t;
+} __attribute__((packed)) hfs_dxinfo_t;
union hfs_finder_info {
struct {
@@ -189,7 +189,7 @@ union hfs_finder_info {
struct hfs_bkey {
hfs_byte_t KeyLen; /* number of bytes in the key */
hfs_byte_t value[1]; /* (KeyLen) bytes of key */
-};
+} __attribute__((packed));
/* Cast to a pointer to a generic bkey */
#define HFS_BKEY(X) (((void)((X)->KeyLen)), ((struct hfs_bkey *)(X)))
@@ -200,7 +200,7 @@ struct hfs_cat_key {
hfs_byte_t Resrv1; /* padding */
hfs_lword_t ParID; /* CNID of the parent dir */
struct hfs_name CName; /* The filename of the entry */
-};
+} __attribute__((packed));
/* The key used in the extents b-tree: */
struct hfs_ext_key {
@@ -208,7 +208,7 @@ struct hfs_ext_key {
hfs_byte_t FkType; /* HFS_FK_{DATA,RSRC} */
hfs_lword_t FNum; /* The File ID of the file */
hfs_word_t FABN; /* allocation blocks number*/
-};
+} __attribute__((packed));
/*======== Data structures kept in memory ========*/
diff --git a/fs/hfs/hfs_btree.h b/fs/hfs/hfs_btree.h
index 97423b350..39d6df4d5 100644
--- a/fs/hfs/hfs_btree.h
+++ b/fs/hfs/hfs_btree.h
@@ -90,7 +90,7 @@ struct BTHdrRec {
hfs_byte_t bthResv2; /* reserved */
hfs_lword_t bthAtrb; /* (F) attributes */
hfs_lword_t bthResv3[16]; /* Reserved */
-};
+} __attribute__((packed));
/*
* struct NodeDescriptor
@@ -112,7 +112,7 @@ struct NodeDescriptor {
hfs_byte_t ndNHeight; /* (F) The level of this node (leaves=1) */
hfs_word_t ndNRecs; /* (V) The number of records in this node */
hfs_word_t ndResv2; /* Reserved */
-};
+} __attribute__((packed));
/*
* typedef hfs_cmpfn
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
index 386a6ae79..b44fdafc8 100644
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -71,7 +71,7 @@ struct raw_mdb {
hfs_byte_t drXTExtRec[12]; /* extents B-tree's first 3 extents */
hfs_lword_t drCTFlSize; /* bytes in the catalog B-tree */
hfs_byte_t drCTExtRec[12]; /* catalog B-tree's first 3 extents */
-};
+} __attribute__((packed));
/*================ Global functions ================*/
diff --git a/fs/hfs/part_tbl.c b/fs/hfs/part_tbl.c
index 12922c6d7..2392a0791 100644
--- a/fs/hfs/part_tbl.c
+++ b/fs/hfs/part_tbl.c
@@ -77,7 +77,7 @@ struct old_pmap {
hfs_lword_t pdSize;
hfs_lword_t pdFSID;
} pdEntry[42];
-};
+} __attribute__((packed));
/*================ File-local functions ================*/
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index dee75d7d0..b09ad98ea 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -326,7 +326,6 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry)
if (r != 2) {
inode->i_nlink--;
hpfs_unlock_2inodes(dir, inode);
- d_delete(dentry);
} else { /* no space for deleting, try to truncate file */
struct iattr newattrs;
int err;
@@ -388,7 +387,6 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
dir->i_nlink--;
inode->i_nlink = 0;
hpfs_unlock_2inodes(dir, inode);
- d_delete(dentry);
} else hpfs_unlock_2inodes(dir, inode);
return r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
}
diff --git a/fs/inode.c b/fs/inode.c
index 1bacb24a7..64373d6ad 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -377,7 +377,7 @@ static int invalidate_list(struct list_head *head, struct super_block * sb, stru
*
* Discard all of the inodes for a given superblock. If the discard
* fails because there are busy inodes then a non zero value is returned.
- * If the discard is successful all the inodes are dicarded.
+ * If the discard is successful all the inodes have been discarded.
*/
int invalidate_inodes(struct super_block * sb)
@@ -470,7 +470,7 @@ int shrink_icache_memory(int priority, int gfp_mask)
/*
* Called with the inode lock held.
* NOTE: we are not increasing the inode-refcount, you must call __iget()
- * by hand after calling find_inode now! This simplify iunique and won't
+ * by hand after calling find_inode now! This simplifies iunique and won't
* add any additional branch in the common code.
*/
static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 376eed9cc..cc3025ee3 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -233,11 +233,21 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
struct rpc_clnt *clnt;
struct nlm_args *argp = &req->a_args;
struct nlm_res *resp = &req->a_res;
+ struct file *filp = argp->lock.fl.fl_file;
+ struct rpc_message msg;
int status;
dprintk("lockd: call procedure %s on %s\n",
nlm_procname(proc), host->h_name);
+ msg.rpc_proc = proc;
+ msg.rpc_argp = argp;
+ msg.rpc_resp = resp;
+ if (filp)
+ msg.rpc_cred = nfs_file_cred(filp);
+ else
+ msg.rpc_cred = NULL;
+
do {
if (host->h_reclaiming && !argp->reclaim) {
interruptible_sleep_on(&host->h_gracewait);
@@ -249,7 +259,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
return -ENOLCK;
/* Perform the RPC call. If an error occurs, try again */
- if ((status = rpc_call(clnt, proc, argp, resp, 0)) < 0) {
+ if ((status = rpc_call_sync(clnt, &msg, 0)) < 0) {
dprintk("lockd: rpc_call returned error %d\n", -status);
switch (status) {
case -EPROTONOSUPPORT:
@@ -330,11 +340,31 @@ int
nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
{
struct nlm_host *host = req->a_host;
- int status;
+ struct rpc_clnt *clnt;
+ struct nlm_args *argp = &req->a_args;
+ struct nlm_res *resp = &req->a_res;
+ struct file *file = argp->lock.fl.fl_file;
+ struct rpc_message msg;
+ int status;
+ dprintk("lockd: call procedure %s on %s (async)\n",
+ nlm_procname(proc), host->h_name);
+
+ /* If we have no RPC client yet, create one. */
+ if ((clnt = nlm_bind_host(host)) == NULL)
+ return -ENOLCK;
+
+ /* bootstrap and kick off the async RPC call */
+ msg.rpc_proc = proc;
+ msg.rpc_argp = argp;
+ msg.rpc_resp =resp;
+ if (file)
+ msg.rpc_cred = nfs_file_cred(file);
+ else
+ msg.rpc_cred = NULL;
/* Increment host refcount */
nlm_get_host(host);
- status = nlmsvc_async_call(req, proc, callback);
+ status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
if (status < 0)
nlm_release_host(host);
return status;
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 97a9d27ef..279fcc3c1 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -533,8 +533,10 @@ callback:
nlmsvc_insert_block(block, jiffies + 30 * HZ);
/* Call the client */
- nlmclnt_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
- nlmsvc_grant_callback);
+ nlm_get_host(block->b_call.a_host);
+ if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
+ nlmsvc_grant_callback) < 0)
+ nlm_release_host(block->b_call.a_host);
up(&file->f_sema);
}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 7dc20ea7c..653c3415a 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -409,7 +409,6 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
mark_inode_dirty(dir);
- d_delete(dentry);
retval = 0;
end_rmdir:
brelse(bh);
@@ -444,7 +443,6 @@ static int minix_unlink(struct inode * dir, struct dentry *dentry)
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
mark_inode_dirty(inode);
- d_delete(dentry); /* This also frees the inode */
retval = 0;
end_unlink:
brelse(bh);
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 612bd6597..bcb40df90 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -337,7 +337,6 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry)
dir->i_nlink--;
mark_inode_dirty(inode);
mark_inode_dirty(dir);
- d_delete(dentry);
res = 0;
rmdir_done:
@@ -432,7 +431,6 @@ int msdos_unlink( struct inode *dir, struct dentry *dentry)
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
mark_inode_dirty(dir);
- d_delete(dentry); /* This also frees the inode */
res = 0;
unlink_done:
return res;
diff --git a/fs/namei.c b/fs/namei.c
index 67f8c0a18..501000381 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -902,20 +902,18 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
if (nd->last.name[nd->last.len])
goto exit;
- dir = dget(nd->dentry);
+ dir = nd->dentry;
down(&dir->d_inode->i_sem);
dentry = lookup_hash(&nd->last, nd->dentry);
error = PTR_ERR(dentry);
if (IS_ERR(dentry)) {
up(&dir->d_inode->i_sem);
- dput(dir);
goto exit;
}
if (dentry->d_inode) {
up(&dir->d_inode->i_sem);
- dput(dir);
error = -EEXIST;
if (flag & O_EXCL)
goto exit_dput;
@@ -940,12 +938,12 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
goto exit;
} else {
error = vfs_create(dir->d_inode, dentry, mode);
+ up(&dir->d_inode->i_sem);
/* Don't check for write permission, don't truncate */
acc_mode = 0;
flag &= ~O_TRUNC;
dput(nd->dentry);
nd->dentry = dentry;
- unlock_dir(dir);
if (error)
goto exit;
}
@@ -1219,6 +1217,8 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
if (!error)
dentry->d_inode->i_flags |= S_DEAD;
double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
+ if (!error)
+ d_delete(dentry);
dput(dentry);
return error;
@@ -1276,6 +1276,8 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
if (dir->i_op && dir->i_op->unlink) {
DQUOT_INIT(dir);
error = dir->i_op->unlink(dir, dentry);
+ if (!error)
+ d_delete(dentry);
}
}
up(&dir->i_zombie);
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index f5a5856f3..55daea198 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -71,7 +71,7 @@ struct inode_operations ncp_dir_inode_operations =
static int ncp_lookup_validate(struct dentry *, int);
static int ncp_hash_dentry(struct dentry *, struct qstr *);
static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
-static void ncp_delete_dentry(struct dentry *);
+static int ncp_delete_dentry(struct dentry *);
struct dentry_operations ncp_dentry_operations =
{
@@ -119,32 +119,22 @@ ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
/*
* This is the callback from dput() when d_count is going to 0.
- * We use this to unhash dentries with bad inodes and close files.
+ * We use this to unhash dentries with bad inodes.
+ * Closing files can be safely postponed until iput() - it's done there anyway.
*/
-static void
+static int
ncp_delete_dentry(struct dentry * dentry)
{
struct inode *inode = dentry->d_inode;
- if (inode)
- {
+ if (inode) {
if (is_bad_inode(inode))
- {
- d_drop(dentry);
- }
- /*
- * Lock the superblock, then recheck the dentry count.
- * (Somebody might have used it again ...)
- */
- if (dentry->d_count == 1 && NCP_FINFO(inode)->opened) {
- PPRINTK("ncp_delete_dentry: closing file %s/%s\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- ncp_make_closed(inode);
- }
+ return 1;
} else
{
/* N.B. Unhash negative dentries? */
}
+ return 0;
}
static inline int
@@ -1000,7 +990,6 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
case 0x00:
DPRINTK("ncp: removed %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- d_delete(dentry);
break;
case 0x85:
case 0x8A:
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 2d2ee4a02..f35ef3bdb 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -35,8 +35,6 @@
#define NFS_PARANOIA 1
/* #define NFS_DEBUG_VERBOSE 1 */
-static int nfs_safe_remove(struct dentry *);
-
static int nfs_readdir(struct file *, void *, filldir_t);
static struct dentry *nfs_lookup(struct inode *, struct dentry *);
static int nfs_create(struct inode *, struct dentry *, int);
@@ -71,6 +69,70 @@ struct inode_operations nfs_dir_inode_operations = {
};
typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
+typedef struct {
+ struct file *file;
+ struct page *page;
+ unsigned long page_index;
+ unsigned page_offset;
+ u64 target;
+ struct nfs_entry *entry;
+ decode_dirent_t decode;
+ int plus;
+ int error;
+} nfs_readdir_descriptor_t;
+
+/* Now we cache directories properly, by stuffing the dirent
+ * data directly in the page cache.
+ *
+ * Inode invalidation due to refresh etc. takes care of
+ * _everything_, no sloppy entry flushing logic, no extraneous
+ * copying, network direct to page cache, the way it was meant
+ * to be.
+ *
+ * NOTE: Dirent information verification is done always by the
+ * page-in of the RPC reply, nowhere else, this simplies
+ * things substantially.
+ */
+static
+int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
+{
+ struct file *file = desc->file;
+ struct inode *inode = file->f_dentry->d_inode;
+ void *buffer = (void *)kmap(page);
+ int plus = NFS_USE_READDIRPLUS(inode);
+ int error;
+
+ dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
+
+ again:
+ error = NFS_PROTO(inode)->readdir(file, desc->entry->cookie, buffer,
+ NFS_SERVER(inode)->dtsize, plus);
+ /* We requested READDIRPLUS, but the server doesn't grok it */
+ if (desc->plus && error == -ENOTSUPP) {
+ NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
+ plus = 0;
+ goto again;
+ }
+ if (error < 0)
+ goto error;
+ SetPageUptodate(page);
+ kunmap(page);
+ /* Ensure consistent page alignment of the data.
+ * Note: assumes we have exclusive access to this mapping either
+ * throught inode->i_sem or some other mechanism.
+ */
+ if (page->index == 0)
+ invalidate_inode_pages(inode);
+ UnlockPage(page);
+ return 0;
+ error:
+ SetPageError(page);
+ kunmap(page);
+ UnlockPage(page);
+ invalidate_inode_pages(inode);
+ desc->error = error;
+ return -EIO;
+}
/*
* Given a pointer to a buffer that has already been filled by a call
@@ -81,309 +143,217 @@ typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
* read.
*/
static inline
-long find_dirent(struct page *page, loff_t offset,
- struct nfs_entry *entry,
- decode_dirent_t decode, int plus, int use_cookie)
+int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page)
{
- u8 *p = (u8 *)kmap(page),
- *start = p;
- unsigned long base = page_offset(page),
- pg_offset = 0;
- int loop_count = 0;
+ struct nfs_entry *entry = desc->entry;
+ char *start = (char *)kmap(page),
+ *p = start;
+ int loop_count = 0,
+ status = 0;
- if (!p)
- return -EIO;
for(;;) {
- p = (u8*)decode((__u32*)p, entry, plus);
- if (IS_ERR(p))
+ p = (char *)desc->decode((u32*)p, entry, desc->plus);
+ if (IS_ERR(p)) {
+ status = PTR_ERR(p);
break;
- pg_offset = p - start;
- entry->prev = entry->offset;
- entry->offset = base + pg_offset;
- if ((use_cookie ? entry->cookie : entry->offset) > offset)
+ }
+ desc->page_offset = p - start;
+ dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie);
+ if (entry->prev_cookie == desc->target)
break;
if (loop_count++ > 200) {
loop_count = 0;
schedule();
}
}
-
kunmap(page);
- return (IS_ERR(p)) ? PTR_ERR(p) : (long)pg_offset;
+ dfprintk(VFS, "NFS: find_dirent() returns %d\n", status);
+ return status;
}
/*
* Find the given page, and call find_dirent() in order to try to
* return the next entry.
- *
- * Returns -EIO if the page is not available, or up to date.
*/
static inline
-long find_dirent_page(struct inode *inode, loff_t offset,
- struct nfs_entry *entry)
+int find_dirent_page(nfs_readdir_descriptor_t *desc)
{
- decode_dirent_t decode = NFS_PROTO(inode)->decode_dirent;
+ struct inode *inode = desc->file->f_dentry->d_inode;
struct page *page;
- unsigned long index = entry->offset >> PAGE_CACHE_SHIFT;
- long status = -EIO;
- int plus = NFS_USE_READDIRPLUS(inode),
- use_cookie = NFS_MONOTONE_COOKIES(inode);
-
- dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", entry->offset & PAGE_CACHE_MASK);
-
- if (entry->page)
- page_cache_release(entry->page);
-
- page = find_get_page(&inode->i_data, index);
+ unsigned long index = desc->page_index;
+ int status;
- if (page && Page_Uptodate(page))
- status = find_dirent(page, offset, entry, decode, plus, use_cookie);
+ dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", desc->page_index);
- /* NB: on successful return we will be holding the page */
- if (status < 0) {
- entry->page = NULL;
- if (page)
- page_cache_release(page);
- } else
- entry->page = page;
+ if (desc->page) {
+ page_cache_release(desc->page);
+ desc->page = NULL;
+ }
- dfprintk(VFS, "NFS: find_dirent_page() returns %ld\n", status);
+ page = read_cache_page(&inode->i_data, index,
+ (filler_t *)nfs_readdir_filler, desc);
+ if (IS_ERR(page)) {
+ status = PTR_ERR(page);
+ goto out;
+ }
+ if (!Page_Uptodate(page))
+ goto read_error;
+
+ /* NOTE: Someone else may have changed the READDIRPLUS flag */
+ desc->plus = NFS_USE_READDIRPLUS(inode);
+ status = find_dirent(desc, page);
+ if (status >= 0)
+ desc->page = page;
+ else
+ page_cache_release(page);
+ out:
+ dfprintk(VFS, "NFS: find_dirent_page() returns %d\n", status);
return status;
+ read_error:
+ page_cache_release(page);
+ return -EIO;
}
-
/*
* Recurse through the page cache pages, and return a
* filled nfs_entry structure of the next directory entry if possible.
*
- * The target for the search is position 'offset'.
- * The latter may either be an offset into the page cache, or (better)
- * a cookie depending on whether we're interested in strictly following
- * the RFC wrt. not assuming monotonicity of cookies or not.
- *
- * For most systems, the latter is more reliable since it naturally
- * copes with holes in the directory.
+ * The target for the search is 'desc->target'.
*/
static inline
-long search_cached_dirent_pages(struct inode *inode, loff_t offset,
- struct nfs_entry *entry)
+int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
{
- long res = 0;
+ int res = 0;
int loop_count = 0;
- dfprintk(VFS, "NFS: search_cached_dirent_pages() searching for cookie %Ld\n", (long long)offset);
+ dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target);
for (;;) {
- res = find_dirent_page(inode, offset, entry);
- if (res == -EAGAIN) {
- /* Align to beginning of next page */
- entry->offset &= PAGE_CACHE_MASK;
- entry->offset += PAGE_CACHE_SIZE;
- }
+ res = find_dirent_page(desc);
if (res != -EAGAIN)
break;
+ /* Align to beginning of next page */
+ desc->page_offset = 0;
+ desc->page_index ++;
if (loop_count++ > 200) {
loop_count = 0;
schedule();
}
}
- if (res < 0 && entry->page) {
- page_cache_release(entry->page);
- entry->page = NULL;
- }
- dfprintk(VFS, "NFS: search_cached_dirent_pages() returned %ld\n", res);
- return res;
-}
-
-
-/* Now we cache directories properly, by stuffing the dirent
- * data directly in the page cache.
- *
- * Inode invalidation due to refresh etc. takes care of
- * _everything_, no sloppy entry flushing logic, no extraneous
- * copying, network direct to page cache, the way it was meant
- * to be.
- *
- * NOTE: Dirent information verification is done always by the
- * page-in of the RPC reply, nowhere else, this simplies
- * things substantially.
- */
-static inline
-long try_to_get_dirent_page(struct file *file, struct inode *inode,
- struct nfs_entry *entry)
-{
- struct dentry *dir = file->f_dentry;
- struct page *page;
- __u32 *p;
- unsigned long index = entry->offset >> PAGE_CACHE_SHIFT;
- long res = 0;
- unsigned int dtsize = NFS_SERVER(inode)->dtsize;
- int plus = NFS_USE_READDIRPLUS(inode);
-
- dfprintk(VFS, "NFS: try_to_get_dirent_page() reading directory page @ index %ld\n", index);
-
- page = grab_cache_page(&inode->i_data, index);
-
- if (!page) {
- res = -ENOMEM;
- goto out;
- }
-
- if (Page_Uptodate(page)) {
- dfprintk(VFS, "NFS: try_to_get_dirent_page(): page already up to date.\n");
- goto unlock_out;
- }
-
- p = (__u32 *)kmap(page);
-
- if (dtsize > PAGE_CACHE_SIZE)
- dtsize = PAGE_CACHE_SIZE;
- res = NFS_PROTO(inode)->readdir(dir, entry->cookie, p, dtsize, plus);
-
- kunmap(page);
-
- if (res < 0)
- goto error;
- if (PageError(page))
- ClearPageError(page);
- SetPageUptodate(page);
-
- unlock_out:
- UnlockPage(page);
- page_cache_release(page);
- out:
- dfprintk(VFS, "NFS: try_to_get_dirent_page() returns %ld\n", res);
+ dfprintk(VFS, "NFS: readdir_search_pagecache() returned %d\n", res);
return res;
- error:
- SetPageError(page);
- goto unlock_out;
}
-/* Recover from a revalidation flush. The case here is that
- * the inode for the directory got invalidated somehow, and
- * all of our cached information is lost. In order to get
- * a correct cookie for the current readdir request from the
- * user, we must (re-)fetch all the older readdir page cache
- * entries.
- *
- * Returns < 0 if some error occurs.
+/*
+ * Once we've found the start of the dirent within a page: fill 'er up...
*/
-static inline
-long refetch_to_readdir(struct file *file, struct inode *inode,
- loff_t off, struct nfs_entry *entry)
+static
+int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
+ filldir_t filldir)
{
- struct nfs_entry my_dirent,
- *dirent = &my_dirent;
- long res;
- int plus = NFS_USE_READDIRPLUS(inode),
- use_cookie = NFS_MONOTONE_COOKIES(inode),
- loop_count = 0;
-
- dfprintk(VFS, "NFS: refetch_to_readdir() searching for cookie %Ld\n", (long long)off);
- *dirent = *entry;
- entry->page = NULL;
-
- for (res = 0;res >= 0;) {
- if (loop_count++ > 200) {
- loop_count = 0;
- schedule();
- }
+ struct file *file = desc->file;
+ struct nfs_entry *entry = desc->entry;
+ char *start = (char *)kmap(desc->page),
+ *p = start + desc->page_offset;
+ unsigned long fileid;
+ int loop_count = 0,
+ res = 0;
- /* Search for last cookie in page cache */
- res = search_cached_dirent_pages(inode, off, dirent);
+ dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target);
- if (res >= 0) {
- /* Cookie was found */
- if ((use_cookie?dirent->cookie:dirent->offset) > off) {
- *entry = *dirent;
- dirent->page = NULL;
- break;
+ for(;;) {
+ /* Note: entry->prev_cookie contains the cookie for
+ * retrieving the current dirent on the server */
+ fileid = nfs_fileid_to_ino_t(entry->ino);
+ res = filldir(dirent, entry->name, entry->len,
+ entry->prev_cookie, fileid);
+ if (res < 0)
+ break;
+ file->f_pos = desc->target = entry->cookie;
+ p = (char *)desc->decode((u32 *)p, entry, desc->plus);
+ if (IS_ERR(p)) {
+ if (PTR_ERR(p) == -EAGAIN) {
+ desc->page_offset = 0;
+ desc->page_index ++;
}
- continue;
- }
-
- if (dirent->page)
- page_cache_release(dirent->page);
- dirent->page = NULL;
-
- if (res != -EIO) {
- *entry = *dirent;
break;
}
-
- /* Read in a new page */
- res = try_to_get_dirent_page(file, inode, dirent);
- if (res == -EBADCOOKIE) {
- memset(dirent, 0, sizeof(*dirent));
- nfs_zap_caches(inode);
- res = 0;
- }
- /* We requested READDIRPLUS, but the server doesn't grok it */
- if (plus && res == -ENOTSUPP) {
- NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
- memset(dirent, 0, sizeof(*dirent));
- nfs_zap_caches(inode);
- plus = 0;
- res = 0;
+ desc->page_offset = p - start;
+ if (loop_count++ > 200) {
+ loop_count = 0;
+ schedule();
}
}
- if (dirent->page)
- page_cache_release(dirent->page);
+ kunmap(desc->page);
+ page_cache_release(desc->page);
+ desc->page = NULL;
- dfprintk(VFS, "NFS: refetch_to_readdir() returns %ld\n", res);
+ dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res);
return res;
}
/*
- * Once we've found the start of the dirent within a page: fill 'er up...
+ * If we cannot find a cookie in our cache, we suspect that this is
+ * because it points to a deleted file, so we ask the server to return
+ * whatever it thinks is the next entry. We then feed this to filldir.
+ * If all goes well, we should then be able to find our way round the
+ * cache on the next call to readdir_search_pagecache();
+ *
+ * NOTE: we cannot add the anonymous page to the pagecache because
+ * the data it contains might not be page aligned. Besides,
+ * we should already have a complete representation of the
+ * directory in the page cache by the time we get here.
*/
-static
-int nfs_do_filldir(struct file *file, struct inode *inode,
- struct nfs_entry *entry, void *dirent, filldir_t filldir)
+static inline
+int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
+ filldir_t filldir)
{
- decode_dirent_t decode = NFS_PROTO(inode)->decode_dirent;
- struct page *page = entry->page;
- __u8 *p,
- *start;
- unsigned long base = page_offset(page),
- offset = entry->offset,
- pg_offset,
- fileid;
- int plus = NFS_USE_READDIRPLUS(inode),
- use_cookie = NFS_MONOTONE_COOKIES(inode),
- loop_count = 0,
- res = 0;
-
- dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ offset %ld\n", entry->offset);
- pg_offset = offset & ~PAGE_CACHE_MASK;
- start = (u8*)kmap(page);
- p = start + pg_offset;
+ struct file *file = desc->file;
+ struct inode *inode = file->f_dentry->d_inode;
+ struct page *page = NULL;
+ u32 *p;
+ int status = -EIO;
+
+ dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target);
+ if (desc->page) {
+ page_cache_release(desc->page);
+ desc->page = NULL;
+ }
- for(;;) {
- /* Note: entry->prev contains the offset of the start of the
- * current dirent */
- fileid = nfs_fileid_to_ino_t(entry->ino);
- if (use_cookie)
- res = filldir(dirent, entry->name, entry->len, entry->prev_cookie, fileid);
+ page = page_cache_alloc();
+ if (!page) {
+ status = -ENOMEM;
+ goto out;
+ }
+ p = (u32 *)kmap(page);
+ status = NFS_PROTO(inode)->readdir(file, desc->target, p,
+ NFS_SERVER(inode)->dtsize, 0);
+ if (status >= 0) {
+ p = desc->decode(p, desc->entry, 0);
+ if (IS_ERR(p))
+ status = PTR_ERR(p);
else
- res = filldir(dirent, entry->name, entry->len, entry->prev, fileid);
- if (res < 0)
- break;
- file->f_pos = (use_cookie) ? entry->cookie : entry->offset;
- p = (u8*)decode((__u32*)p, entry, plus);
- if (!p || IS_ERR(p))
- break;
- pg_offset = p - start;
- entry->prev = entry->offset;
- entry->offset = base + pg_offset;
- if (loop_count++ > 200) {
- loop_count = 0;
- schedule();
- }
+ desc->entry->prev_cookie = desc->target;
}
kunmap(page);
-
- dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ offset %ld; returning = %d\n", entry->offset, res);
- return res;
+ if (status < 0)
+ goto out_release;
+
+ desc->page_index = 0;
+ desc->page_offset = 0;
+ desc->page = page;
+ status = nfs_do_filldir(desc, dirent, filldir);
+
+ /* Reset read descriptor so it searches the page cache from
+ * the start upon the next call to readdir_search_pagecache() */
+ desc->page_index = 0;
+ desc->page_offset = 0;
+ memset(desc->entry, 0, sizeof(*desc->entry));
+ out:
+ dfprintk(VFS, "NFS: uncached_readdir() returns %d\n", status);
+ return status;
+ out_release:
+ page_cache_release(page);
+ goto out;
}
/* The file offset position is now represented as a true offset into the
@@ -393,10 +363,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
- struct page *page;
- struct nfs_entry my_entry,
- *entry = &my_entry;
- loff_t offset;
+ nfs_readdir_descriptor_t my_desc,
+ *desc = &my_desc;
+ struct nfs_entry my_entry;
long res;
res = nfs_revalidate(dentry);
@@ -409,36 +378,41 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
* read from the last dirent to revalidate f_pos
* itself.
*/
- memset(entry, 0, sizeof(*entry));
+ memset(desc, 0, sizeof(*desc));
+ memset(&my_entry, 0, sizeof(my_entry));
- offset = filp->f_pos;
+ desc->file = filp;
+ desc->target = filp->f_pos;
+ desc->entry = &my_entry;
+ desc->decode = NFS_PROTO(inode)->decode_dirent;
- while(!entry->eof) {
- res = search_cached_dirent_pages(inode, offset, entry);
-
- if (res < 0) {
- if (entry->eof)
- break;
- res = refetch_to_readdir(filp, inode, offset, entry);
- if (res < 0)
+ while(!desc->entry->eof) {
+ res = readdir_search_pagecache(desc);
+ if (res == -EBADCOOKIE) {
+ /* This means either end of directory */
+ if (desc->entry->cookie == desc->target) {
+ res = 0;
break;
+ }
+ /* Or that the server has 'lost' a cookie */
+ res = uncached_readdir(desc, dirent, filldir);
+ if (res >= 0)
+ continue;
}
+ if (res < 0)
+ break;
- page = entry->page;
- if (!page)
- printk(KERN_ERR "NFS: Missing page...\n");
- res = nfs_do_filldir(filp, inode, entry, dirent, filldir);
- page_cache_release(page);
- entry->page = NULL;
+ res = nfs_do_filldir(desc, dirent, filldir);
if (res < 0) {
res = 0;
break;
}
- offset = filp->f_pos;
}
- if (entry->page)
- page_cache_release(entry->page);
- if (res < 0 && res != -EBADCOOKIE)
+ if (desc->page)
+ page_cache_release(desc->page);
+ if (desc->error < 0)
+ return desc->error;
+ if (res < 0)
return res;
return 0;
}
@@ -583,26 +557,18 @@ out_bad:
/*
* This is called from dput() when d_count is going to 0.
- * We use it to clean up silly-renamed files.
*/
-static void nfs_dentry_delete(struct dentry *dentry)
+static int nfs_dentry_delete(struct dentry *dentry)
{
dfprintk(VFS, "NFS: dentry_delete(%s/%s, %x)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
dentry->d_flags);
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
- int error;
-
- dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
- /* Unhash it first */
- d_drop(dentry);
- error = nfs_safe_remove(dentry);
- if (error)
- printk("NFS: can't silly-delete %s/%s, error=%d\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name, error);
+ /* Unhash it, so that ->d_iput() would be called */
+ return 1;
}
+ return 0;
}
@@ -627,36 +593,30 @@ static void nfs_dentry_release(struct dentry *dentry)
nfs_fh_free(dentry->d_fsdata);
}
-struct dentry_operations nfs_dentry_operations = {
- d_revalidate: nfs_lookup_revalidate,
- d_delete: nfs_dentry_delete,
- d_release: nfs_dentry_release,
-};
-
-#if 0 /* dead code */
-#ifdef NFS_PARANOIA
/*
- * Display all dentries holding the specified inode.
+ * Called when the dentry loses inode.
+ * We use it to clean up silly-renamed files.
*/
-static void show_dentry(struct list_head * dlist)
+static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
{
- struct list_head *tmp = dlist;
-
- while ((tmp = tmp->next) != dlist) {
- struct dentry * dentry = list_entry(tmp, struct dentry, d_alias);
- const char * unhashed = "";
-
- if (d_unhashed(dentry))
- unhashed = "(unhashed)";
-
- printk("show_dentry: %s/%s, d_count=%d%s\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name, dentry->d_count,
- unhashed);
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+ struct dentry *dir = dentry->d_parent;
+ struct inode *dir_i = dir->d_inode;
+ int error;
+
+ nfs_zap_caches(dir_i);
+ NFS_CACHEINV(inode);
+ error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name);
}
+ iput(inode);
}
-#endif /* NFS_PARANOIA */
-#endif /* 0 */
+
+struct dentry_operations nfs_dentry_operations = {
+ d_revalidate: nfs_lookup_revalidate,
+ d_delete: nfs_dentry_delete,
+ d_release: nfs_dentry_release,
+ d_iput: nfs_dentry_iput,
+};
static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry)
{
@@ -715,7 +675,6 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
nfs_renew_times(dentry);
error = 0;
}
- NFS_CACHEINV(dentry->d_parent->d_inode);
return error;
}
@@ -809,7 +768,6 @@ static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
d_drop(dentry);
#endif
nfs_zap_caches(dir_i);
- dir_i->i_nlink++;
error = NFS_PROTO(dir_i)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
&fattr);
if (!error && fhandle.size != 0)
@@ -830,13 +788,6 @@ static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry)
nfs_zap_caches(dir_i);
error = NFS_PROTO(dir_i)->rmdir(dir, &dentry->d_name);
- /* Update i_nlink and invalidate dentry. */
- if (!error) {
- d_drop(dentry);
- if (dir_i->i_nlink)
- dir_i->i_nlink--;
- }
-
return error;
}
@@ -919,7 +870,7 @@ out:
* Remove a file after making sure there are no pending writes,
* and after checking that the file has only one user.
*
- * We update inode->i_nlink and free the inode prior to the operation
+ * We invalidate the attribute cache and free the inode prior to the operation
* to avoid possible races if the server reuses the inode.
*/
static int nfs_safe_remove(struct dentry *dentry)
@@ -927,28 +878,12 @@ static int nfs_safe_remove(struct dentry *dentry)
struct dentry *dir = dentry->d_parent;
struct inode *dir_i = dir->d_inode;
struct inode *inode = dentry->d_inode;
- int error, rehash = 0;
+ int error = -EBUSY, rehash = 0;
dfprintk(VFS, "NFS: safe_remove(%s/%s, %ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
inode->i_ino);
- /* N.B. not needed now that d_delete is done in advance? */
- error = -EBUSY;
- if (!inode) {
-#ifdef NFS_PARANOIA
-printk("nfs_safe_remove: %s/%s already negative??\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
- }
-
- if (dentry->d_count > 1) {
-#ifdef NFS_PARANOIA
-printk("nfs_safe_remove: %s/%s busy, d_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-#endif
- goto out;
- }
/*
* Unhash the dentry while we remove the file ...
*/
@@ -956,24 +891,26 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
d_drop(dentry);
rehash = 1;
}
+ if (dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+ printk("nfs_safe_remove: %s/%s busy, d_count=%d\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ dentry->d_count);
+#endif
+ goto out;
+ }
nfs_zap_caches(dir_i);
+ NFS_CACHEINV(inode);
error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name);
if (error < 0)
goto out;
/*
- * Update i_nlink and free the inode
+ * Free the inode
*/
- if (inode) {
- if (inode->i_nlink)
- inode->i_nlink --;
- d_delete(dentry);
- }
- /*
- * Rehash the negative dentry if the operation succeeded.
- */
- if (rehash)
- d_add(dentry, NULL);
+ d_delete(dentry);
out:
+ if (rehash)
+ d_rehash(dentry);
return error;
}
@@ -1067,14 +1004,8 @@ nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
*/
d_drop(dentry);
nfs_zap_caches(dir_i);
+ NFS_CACHEINV(inode);
error = NFS_PROTO(dir_i)->link(old_dentry, dir, &dentry->d_name);
- if (!error) {
- /*
- * Update the link count immediately, as some apps
- * (e.g. pine) test this after making a link.
- */
- inode->i_nlink++;
- }
return error;
}
@@ -1107,8 +1038,17 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
{
struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode;
- struct dentry *dentry = NULL;
- int error, rehash = 0;
+ struct dentry *dentry = NULL, *rehash = NULL;
+ int error = -EBUSY;
+
+ /*
+ * To prevent any new references to the target during the rename,
+ * we unhash the dentry and free the inode in advance.
+ */
+ if (!d_unhashed(new_dentry)) {
+ d_drop(new_dentry);
+ rehash = new_dentry;
+ }
dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n",
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
@@ -1125,7 +1065,6 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
*/
if (!new_inode)
goto go_ahead;
- error = -EBUSY;
if (S_ISDIR(new_inode->i_mode))
goto out;
else if (new_dentry->d_count > 1) {
@@ -1139,10 +1078,10 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
/* silly-rename the existing target ... */
err = nfs_sillyrename(new_dir, new_dentry);
if (!err) {
- new_dentry = dentry;
+ new_dentry = rehash = dentry;
new_inode = NULL;
- /* hash the replacement target */
- d_add(new_dentry, NULL);
+ /* instantiate the replacement target */
+ d_instantiate(new_dentry, NULL);
}
/* dentry still busy? */
@@ -1166,14 +1105,6 @@ go_ahead:
shrink_dcache_parent(old_dentry);
}
- /*
- * To prevent any new references to the target during the rename,
- * we unhash the dentry and free the inode in advance.
- */
- if (!d_unhashed(new_dentry)) {
- d_drop(new_dentry);
- rehash = 1;
- }
if (new_inode)
d_delete(new_dentry);
@@ -1183,15 +1114,12 @@ go_ahead:
&old_dentry->d_name,
new_dentry->d_parent,
&new_dentry->d_name);
- NFS_CACHEINV(old_dir);
- NFS_CACHEINV(new_dir);
- /* Update the dcache if needed */
+out:
if (rehash)
- d_add(new_dentry, NULL);
+ d_rehash(rehash);
if (!error && !S_ISDIR(old_inode->i_mode))
d_move(old_dentry, new_dentry);
-out:
/* new dentry created? */
if (dentry)
dput(dentry);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 2d71aa7b5..44e3030c3 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -555,22 +555,18 @@ nfs_free_dentries(struct inode *inode)
struct list_head *tmp, *head = &inode->i_dentry;
int unhashed;
-restart:
+ if (S_ISDIR(inode->i_mode)) {
+ struct dentry *dentry = d_find_alias(inode);
+ if (dentry) {
+ shrink_dcache_parent(dentry);
+ dput(dentry);
+ }
+ }
+ d_prune_aliases(inode);
tmp = head;
unhashed = 0;
while ((tmp = tmp->next) != head) {
struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
- dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
- dentry->d_parent->d_name.name, dentry->d_name.name,
- dentry->d_count, !d_unhashed(dentry));
- if (!list_empty(&dentry->d_subdirs))
- shrink_dcache_parent(dentry);
- if (!dentry->d_count) {
- dget(dentry);
- d_drop(dentry);
- dput(dentry);
- goto restart;
- }
if (d_unhashed(dentry))
unhashed++;
}
@@ -895,11 +891,20 @@ nfs_revalidate(struct dentry *dentry)
*/
int nfs_open(struct inode *inode, struct file *filp)
{
+ struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth;
+ struct rpc_cred *cred = rpcauth_lookupcred(auth, 0);
+
+ filp->private_data = cred;
return 0;
}
int nfs_release(struct inode *inode, struct file *filp)
{
+ struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth;
+ struct rpc_cred *cred = nfs_file_cred(filp);
+
+ if (cred)
+ rpcauth_releasecred(auth, cred);
return 0;
}
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 1dd1553ba..a8b61c2e7 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -485,13 +485,6 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
break;
}
}
- p++; /* EOF flag */
-
- if (p > end) {
- printk(KERN_NOTICE
- "NFS: short packet in readdir reply!\n");
- return -errno_NFSERR_IO;
- }
return nr;
}
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 67de662a6..921841ba3 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -138,14 +138,16 @@ nfs3_proc_readlink(struct dentry *dentry, void *buffer, unsigned int buflen)
}
static int
-nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+nfs3_proc_read(struct file *file, struct nfs_fattr *fattr, int flags,
loff_t offset, unsigned int count, void *buffer, int *eofp)
{
+ struct dentry *dentry = file->f_dentry;
+ struct rpc_cred *cred = nfs_file_cred(file);
struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1,
{{buffer, count}, {0,0}, {0,0}, {0,0},
{0,0}, {0,0}, {0,0}, {0,0}} };
struct nfs_readres res = { fattr, count, 0 };
- struct rpc_message msg = { NFS3PROC_READ, &arg, &res, NULL };
+ struct rpc_message msg = { NFS3PROC_READ, &arg, &res, cred };
int status;
dprintk("NFS call read %d @ %Ld\n", count, (long long)offset);
@@ -157,16 +159,18 @@ nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
}
static int
-nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+nfs3_proc_write(struct file *file, struct nfs_fattr *fattr, int flags,
loff_t offset, unsigned int count,
void *buffer, struct nfs_writeverf *verf)
{
+ struct dentry *dentry = file->f_dentry;
+ struct rpc_cred *cred = nfs_file_cred(file);
struct nfs_writeargs arg = { NFS_FH(dentry), offset, count,
NFS_FILE_SYNC, 1,
{{buffer, count}, {0,0}, {0,0}, {0,0},
{0,0}, {0,0}, {0,0}, {0,0}} };
struct nfs_writeres res = { fattr, verf, 0 };
- struct rpc_message msg = { NFS3PROC_WRITE, &arg, &res, NULL };
+ struct rpc_message msg = { NFS3PROC_WRITE, &arg, &res, cred };
int status, rpcflags = 0;
dprintk("NFS call write %d @ %Ld\n", count, (long long)offset);
@@ -369,13 +373,15 @@ nfs3_proc_rmdir(struct dentry *dir, struct qstr *name)
* readdirplus.
*/
static int
-nfs3_proc_readdir(struct dentry *dir, u64 cookie, void *entry,
+nfs3_proc_readdir(struct file *file, u64 cookie, void *entry,
unsigned int size, int plus)
{
+ struct dentry *dir = file->f_dentry;
+ struct rpc_cred *cred = nfs_file_cred(file);
struct nfs_fattr dir_attr;
struct nfs3_readdirargs arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 };
struct nfs3_readdirres res = { &dir_attr, 0, 0, 0, 0 };
- struct rpc_message msg = { NFS3PROC_READDIR, &arg, &res, NULL };
+ struct rpc_message msg = { NFS3PROC_READDIR, &arg, &res, cred };
u32 *verf = NFS_COOKIEVERF(dir->d_inode);
int status;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index d6d532217..0abf65af2 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -122,14 +122,16 @@ nfs_proc_readlink(struct dentry *dentry, void *buffer, unsigned int bufsiz)
}
static int
-nfs_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+nfs_proc_read(struct file *file, struct nfs_fattr *fattr, int flags,
loff_t offset, unsigned int count, void *buffer, int *eofp)
{
+ struct dentry *dentry = file->f_dentry;
+ struct rpc_cred *cred = nfs_file_cred(file);
struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1,
{{ buffer, count }, {0,0}, {0,0}, {0,0},
{0,0}, {0,0}, {0,0}, {0,0}} };
struct nfs_readres res = { fattr, count, 0};
- struct rpc_message msg = { NFSPROC_READ, &arg, &res, NULL };
+ struct rpc_message msg = { NFSPROC_READ, &arg, &res, cred };
int status;
dprintk("NFS call read %d @ %Ld\n", count, (long long)offset);
@@ -142,16 +144,18 @@ nfs_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
}
static int
-nfs_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int how,
+nfs_proc_write(struct file *file, struct nfs_fattr *fattr, int how,
loff_t offset, unsigned int count,
void *buffer, struct nfs_writeverf *verf)
{
+ struct dentry *dentry = file->f_dentry;
+ struct rpc_cred *cred = nfs_file_cred(file);
struct nfs_writeargs arg = {NFS_FH(dentry), offset, count,
NFS_FILE_SYNC, 1,
{{buffer, count}, {0,0}, {0,0}, {0,0},
{0,0}, {0,0}, {0,0}, {0,0}}};
struct nfs_writeres res = {fattr, verf, count};
- struct rpc_message msg = { NFSPROC_WRITE, &arg, &res, NULL };
+ struct rpc_message msg = { NFSPROC_WRITE, &arg, &res, cred };
int status, flags = 0;
dprintk("NFS call write %d @ %Ld\n", count, (long long)offset);
@@ -311,12 +315,14 @@ nfs_proc_rmdir(struct dentry *dir, struct qstr *name)
* from nfs_readdir by calling the decode_entry function directly.
*/
static int
-nfs_proc_readdir(struct dentry *dir, __u64 cookie, void *entry,
+nfs_proc_readdir(struct file *file, __u64 cookie, void *entry,
unsigned int size, int plus)
{
+ struct dentry *dir = file->f_dentry;
+ struct rpc_cred *cred = nfs_file_cred(file);
struct nfs_readdirargs arg;
struct nfs_readdirres res;
- struct rpc_message msg = { NFSPROC_READDIR, &arg, &res, NULL };
+ struct rpc_message msg = { NFSPROC_READDIR, &arg, &res, cred };
struct nfs_server *server = NFS_DSERVER(dir);
int status;
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 1c70ae58d..b15f50e61 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -83,8 +83,9 @@ static void nfs_readdata_release(struct rpc_task *task)
* Read a page synchronously.
*/
static int
-nfs_readpage_sync(struct dentry *dentry, struct page *page)
+nfs_readpage_sync(struct file *file, struct page *page)
{
+ struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
struct nfs_fattr fattr;
loff_t offset = page_offset(page);
@@ -112,7 +113,7 @@ nfs_readpage_sync(struct dentry *dentry, struct page *page)
(long long)offset, rsize, buffer);
lock_kernel();
- result = NFS_PROTO(inode)->read(dentry, &fattr, flags, offset,
+ result = NFS_PROTO(inode)->read(file, &fattr, flags, offset,
rsize, buffer, &eof);
unlock_kernel();
nfs_refresh_inode(inode, &fattr);
@@ -195,9 +196,9 @@ nfs_mark_request_read(struct nfs_page *req)
}
static int
-nfs_readpage_async(struct dentry *dentry, struct page *page)
+nfs_readpage_async(struct file *file, struct page *page)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_dentry->d_inode;
struct nfs_page *req, *new = NULL;
int result;
@@ -227,7 +228,7 @@ nfs_readpage_async(struct dentry *dentry, struct page *page)
}
result = -ENOMEM;
- new = nfs_create_request(dentry, page, 0, PAGE_CACHE_SIZE);
+ new = nfs_create_request(file, page, 0, PAGE_CACHE_SIZE);
if (!new)
break;
}
@@ -462,20 +463,16 @@ nfs_readpage_result(struct rpc_task *task)
/*
* Read a page over NFS.
* We read the page synchronously in the following cases:
- * - The file is a swap file. Swap-ins are always sync operations,
- * so there's no need bothering to make async reads 100% fail-safe.
* - The NFS rsize is smaller than PAGE_CACHE_SIZE. We could kludge our way
* around this by creating several consecutive read requests, but
* that's hardly worth it.
* - The error flag is set for this page. This happens only when a
* previous async read operation failed.
- * - The server is congested.
*/
int
nfs_readpage(struct file *file, struct page *page)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_dentry->d_inode;
int error;
dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
@@ -493,11 +490,11 @@ nfs_readpage(struct file *file, struct page *page)
error = -1;
if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
- error = nfs_readpage_async(dentry, page);
+ error = nfs_readpage_async(file, page);
if (error >= 0)
goto out;
- error = nfs_readpage_sync(dentry, page);
+ error = nfs_readpage_sync(file, page);
if (error < 0 && IS_SWAPFILE(inode))
printk("Aiee.. nfs swap-in of page failed!\n");
out:
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 52af85acb..464776ac3 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -89,8 +89,7 @@ struct nfs_write_data {
/*
* Local function declarations
*/
-static struct nfs_page * nfs_update_request(struct file*, struct dentry *,
- struct page *page,
+static struct nfs_page * nfs_update_request(struct file*, struct page *page,
unsigned int, unsigned int);
static void nfs_strategy(struct inode *inode);
static void nfs_writeback_done(struct rpc_task *);
@@ -168,9 +167,10 @@ nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
* Offset is the data offset within the page.
*/
static int
-nfs_writepage_sync(struct dentry *dentry, struct page *page,
+nfs_writepage_sync(struct file *file, struct page *page,
unsigned int offset, unsigned int count)
{
+ struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
loff_t base;
unsigned int wsize = NFS_SERVER(inode)->wsize;
@@ -193,7 +193,7 @@ nfs_writepage_sync(struct dentry *dentry, struct page *page,
if (count < wsize && !IS_SWAPFILE(inode))
wsize = count;
- result = NFS_PROTO(inode)->write(dentry, &fattr, flags,
+ result = NFS_PROTO(inode)->write(file, &fattr, flags,
base, wsize, buffer, &verf);
nfs_write_attributes(inode, &fattr);
@@ -229,18 +229,18 @@ io_error:
}
static int
-nfs_writepage_async(struct file *file, struct dentry *dentry, struct page *page,
+nfs_writepage_async(struct file *file, struct page *page,
unsigned int offset, unsigned int count)
{
struct nfs_page *req;
int status;
- req = nfs_update_request(file, dentry, page, offset, count);
+ req = nfs_update_request(file, page, offset, count);
status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
if (status < 0)
goto out;
nfs_release_request(req);
- nfs_strategy(dentry->d_inode);
+ nfs_strategy(file->f_dentry->d_inode);
out:
return status;
}
@@ -251,8 +251,7 @@ nfs_writepage_async(struct file *file, struct dentry *dentry, struct page *page,
int
nfs_writepage(struct file *file, struct page *page)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_dentry->d_inode;
unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
unsigned offset = PAGE_CACHE_SIZE;
int err;
@@ -267,11 +266,11 @@ nfs_writepage(struct file *file, struct page *page)
return -EIO;
do_it:
if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
- err = nfs_writepage_async(file, dentry, page, 0, offset);
+ err = nfs_writepage_async(file, page, 0, offset);
if (err >= 0)
goto out_ok;
}
- err = nfs_writepage_sync(dentry, page, 0, offset);
+ err = nfs_writepage_sync(file, page, 0, offset);
if ( err == offset)
goto out_ok;
return err;
@@ -476,10 +475,12 @@ nfs_mark_request_commit(struct nfs_page *req)
* Page must be locked by the caller. This makes sure we never create
* two different requests for the same page, and avoids possible deadlock
* when we reach the hard limit on the number of dirty pages.
+ * It should be safe to sleep here.
*/
-struct nfs_page *nfs_create_request(struct dentry *dentry, struct page *page,
+struct nfs_page *nfs_create_request(struct file *file, struct page *page,
unsigned int offset, unsigned int count)
{
+ struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
struct nfs_page *req = NULL;
@@ -531,8 +532,10 @@ struct nfs_page *nfs_create_request(struct dentry *dentry, struct page *page,
page_cache_get(page);
req->wb_offset = offset;
req->wb_bytes = count;
- req->wb_dentry = dget(dentry);
- req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+ req->wb_file = file;
+ get_file(file);
+ req->wb_dentry = dentry;
+ req->wb_cred = nfs_file_cred(file);
req->wb_count = 1;
/* register request's existence */
@@ -573,12 +576,7 @@ nfs_release_request(struct nfs_page *req)
if (NFS_WBACK_BUSY(req))
printk(KERN_ERR "NFS: Request released while still locked!\n");
- rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred);
- lock_kernel();
- if (req->wb_file)
- fput(req->wb_file);
- dput(req->wb_dentry);
- unlock_kernel();
+ fput(req->wb_file);
page_cache_release(page);
nfs_page_free(req);
/* wake up anyone waiting to allocate a request */
@@ -789,10 +787,6 @@ int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned
if (prev) {
if (req->wb_file != prev->wb_file)
break;
- if (req->wb_dentry != prev->wb_dentry)
- break;
- if (req->wb_cred != prev->wb_cred)
- break;
if (page_index(req->wb_page) != page_index(prev->wb_page)+1)
break;
@@ -818,10 +812,10 @@ int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned
* Note: Should always be called with the Page Lock held!
*/
static struct nfs_page *
-nfs_update_request(struct file* file, struct dentry *dentry, struct page *page,
+nfs_update_request(struct file* file, struct page *page,
unsigned int offset, unsigned int bytes)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_dentry->d_inode;
struct nfs_page *req, *new = NULL;
unsigned long rqend, end;
@@ -856,21 +850,14 @@ nfs_update_request(struct file* file, struct dentry *dentry, struct page *page,
}
spin_unlock(&nfs_wreq_lock);
-
- /* Create the request. It's safe to sleep in this call because
- * we only get here if the page is locked.
- *
+ /*
* If we're over the soft limit, flush out old requests
*/
- if (file && nfs_nr_requests >= MAX_REQUEST_SOFT)
+ if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT)
nfs_wb_file(inode, file);
- new = nfs_create_request(dentry, page, offset, bytes);
+ new = nfs_create_request(file, page, offset, bytes);
if (!new)
return ERR_PTR(-ENOMEM);
- if (file) {
- new->wb_file = file;
- get_file(file);
- }
/* If the region is locked, adjust the timeout */
if (region_locked(inode, new))
new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
@@ -1006,7 +993,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
* page synchronously.
*/
if (NFS_SERVER(inode)->wsize < PAGE_SIZE)
- return nfs_writepage_sync(dentry, page, offset, count);
+ return nfs_writepage_sync(file, page, offset, count);
/*
* Try to find an NFS request corresponding to this page
@@ -1015,7 +1002,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
* it out now.
*/
do {
- req = nfs_update_request(file, dentry, page, offset, count);
+ req = nfs_update_request(file, page, offset, count);
status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
if (status != -EBUSY)
break;
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 79ef12a7b..c47830ff3 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -49,16 +49,21 @@ nfsd_cache_init(void)
struct svc_cacherep *rp;
struct nfscache_head *rh;
size_t i;
+ unsigned long order;
if (cache_initialized)
return;
i = CACHESIZE * sizeof (struct svc_cacherep);
- nfscache = kmalloc (i, GFP_KERNEL);
+ for (order = 0; (PAGE_SIZE << order) < i; order++)
+ ;
+ nfscache = (struct svc_cacherep *)
+ __get_free_pages(GFP_KERNEL, order);
if (!nfscache) {
printk (KERN_ERR "nfsd: cannot allocate %d bytes for reply cache\n", i);
return;
}
+ memset(nfscache, 0, i);
i = HASHSIZE * sizeof (struct nfscache_head);
hash_list = kmalloc (i, GFP_KERNEL);
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index a5fcdcf7d..f681c9bfc 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -812,17 +812,11 @@ fh_put(struct svc_fh *fhp)
{
struct dentry * dentry = fhp->fh_dentry;
if (fhp->fh_dverified) {
+ fhp->fh_dentry = NULL;
fh_unlock(fhp);
fhp->fh_dverified = 0;
- if (!dentry->d_count)
- goto out_bad;
dput(dentry);
nfsd_nr_put++;
}
return;
-
-out_bad:
- printk(KERN_ERR "fh_put: %s/%s has d_count 0!\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- return;
}
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 92eed7559..3b875a445 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -1,4 +1,4 @@
-/* $Id: inode.c,v 1.10 2000/03/24 01:32:51 davem Exp $
+/* $Id: inode.c,v 1.11 2000/05/22 07:29:42 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com)
@@ -870,7 +870,6 @@ static int openpromfs_unlink (struct inode *dir, struct dentry *dentry)
buffer [10 + len] = 0;
prom_feval (buffer);
}
- d_delete(dentry);
return 0;
}
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 7f9ed2ba7..3b252ec63 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -135,6 +135,9 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
case IDE0_MAJOR:
maj = "hd";
break;
+ case MD_MAJOR:
+ unit -= 'a'-'0';
+ break;
}
if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {
unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;
diff --git a/fs/pipe.c b/fs/pipe.c
index 525cd7285..b97851fab 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -465,7 +465,7 @@ fail_page:
return NULL;
}
-static struct vfsmount *pipe_mnt = NULL;
+static struct vfsmount *pipe_mnt;
static struct inode * get_pipe_inode(void)
{
@@ -609,6 +609,7 @@ static struct super_block * pipefs_read_super(struct super_block *sb, void *data
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
+ sb->s_magic = PIPEFS_MAGIC;
sb->s_op = &pipefs_ops;
sb->s_root = d_alloc(NULL, &(const struct qstr) { "pipe:", 5, 0 });
if (!sb->s_root) {
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 2e83c6a4e..d513987d8 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -22,6 +22,7 @@
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/file.h>
+#include <linux/string.h>
/*
* For hysterical raisins we keep the same inumbers as in the old procfs.
@@ -651,6 +652,11 @@ static int pid_fd_revalidate(struct dentry * dentry, int flags)
return 0;
}
+/*
+ * Exceptional case: normally we are not allowed to unhash a busy
+ * directory. In this case, however, we can do it - no aliasing problems
+ * due to the way we treat inodes.
+ */
static int pid_base_revalidate(struct dentry * dentry, int flags)
{
if (dentry->d_inode->u.proc_i.task->p_pptr)
@@ -659,9 +665,9 @@ static int pid_base_revalidate(struct dentry * dentry, int flags)
return 0;
}
-static void pid_delete_dentry(struct dentry * dentry)
+static int pid_delete_dentry(struct dentry * dentry)
{
- d_drop(dentry);
+ return 1;
}
static struct dentry_operations pid_fd_dentry_operations =
@@ -861,6 +867,28 @@ static struct inode_operations proc_base_inode_operations = {
lookup: proc_base_lookup,
};
+/*
+ * /proc/self:
+ */
+static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+ char tmp[30];
+ sprintf(tmp, "%d", current->pid);
+ return vfs_readlink(dentry,buffer,buflen,tmp);
+}
+
+static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ char tmp[30];
+ sprintf(tmp, "%d", current->pid);
+ return vfs_follow_link(nd,tmp);
+}
+
+static struct inode_operations proc_self_inode_operations = {
+ readlink: proc_self_readlink,
+ follow_link: proc_self_follow_link,
+};
+
struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
{
unsigned int pid, c;
@@ -872,6 +900,23 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
pid = 0;
name = dentry->d_name.name;
len = dentry->d_name.len;
+ if (len == 4 && !memcmp(name, "self", 4)) {
+ inode = get_empty_inode();
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ inode->i_sb = dir->i_sb;
+ inode->i_dev = dir->i_sb->s_dev;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_ino = fake_ino(0, PROC_PID_INO);
+ inode->u.proc_i.file = NULL;
+ inode->u.proc_i.task = NULL;
+ inode->i_mode = S_IFLNK|S_IRWXUGO;
+ inode->i_uid = inode->i_gid = 0;
+ inode->i_size = 64;
+ inode->i_op = &proc_self_inode_operations;
+ d_add(dentry, inode);
+ return NULL;
+ }
while (len-- > 0) {
c = *name - '0';
name++;
@@ -916,7 +961,8 @@ void proc_pid_delete_inode(struct inode *inode)
{
if (inode->u.proc_i.file)
fput(inode->u.proc_i.file);
- free_task_struct(inode->u.proc_i.task);
+ if (inode->u.proc_i.task)
+ free_task_struct(inode->u.proc_i.task);
}
#define PROC_NUMBUF 10
@@ -932,7 +978,7 @@ static int get_pid_list(int index, unsigned int *pids)
struct task_struct *p;
int nr_pids = 0;
- index -= FIRST_PROCESS_ENTRY;
+ index--;
read_lock(&tasklist_lock);
for_each_task(p) {
int pid = p->pid;
@@ -953,9 +999,17 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
unsigned int pid_array[PROC_MAXPIDS];
char buf[PROC_NUMBUF];
- unsigned int nr = filp->f_pos;
+ unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
unsigned int nr_pids, i;
+ if (!nr) {
+ ino_t ino = fake_ino(0,PROC_PID_INO);
+ if (filldir(dirent, "self", 4, filp->f_pos, ino) < 0)
+ return 0;
+ filp->f_pos++;
+ nr++;
+ }
+
nr_pids = get_pid_list(nr, pid_array);
for (i = 0; i < nr_pids; i++) {
@@ -963,11 +1017,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
ino_t ino = fake_ino(pid,PROC_PID_INO);
unsigned long j = PROC_NUMBUF;
- do {
- j--;
- buf[j] = '0' + (pid % 10);
- pid /= 10;
- } while (pid);
+ do buf[--j] = '0' + (pid % 10); while (pid/=10);
if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0)
break;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 31e43fab9..1585657a2 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -140,9 +140,13 @@ proc_file_lseek(struct file * file, loff_t offset, int orig)
{
switch (orig) {
case 0:
+ if (offset < 0)
+ return -EINVAL;
file->f_pos = offset;
return(file->f_pos);
case 1:
+ if (offset + file->f_pos < 0)
+ return -EINVAL;
file->f_pos += offset;
return(file->f_pos);
case 2:
@@ -218,10 +222,9 @@ static struct inode_operations proc_link_inode_operations = {
* smarter: we could keep a "volatile" flag in the
* inode to indicate which ones to keep.
*/
-static void
-proc_delete_dentry(struct dentry * dentry)
+static int proc_delete_dentry(struct dentry * dentry)
{
- d_drop(dentry);
+ return 1;
}
static struct dentry_operations proc_dentry_operations =
@@ -340,7 +343,7 @@ static struct inode_operations proc_dir_inode_operations = {
lookup: proc_lookup,
};
-int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
+static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{
int i;
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 13ec76b02..01db469da 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -315,13 +315,12 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
size_t elf_buflen;
int num_vma;
- /* XXX we need to somehow lock vmlist between here
- * and after elf_kcore_store_hdr() returns.
- * For now assume that num_vma does not change (TA)
- */
+ read_lock(&vmlist_lock);
proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen);
- if (buflen == 0 || *fpos >= size)
+ if (buflen == 0 || *fpos >= size) {
+ read_unlock(&vmlist_lock);
return 0;
+ }
/* trim buflen to not go beyond EOF */
if (buflen > size - *fpos)
@@ -335,10 +334,13 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
if (buflen < tsz)
tsz = buflen;
elf_buf = kmalloc(elf_buflen, GFP_ATOMIC);
- if (!elf_buf)
+ if (!elf_buf) {
+ read_unlock(&vmlist_lock);
return -ENOMEM;
+ }
memset(elf_buf, 0, elf_buflen);
elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen);
+ read_unlock(&vmlist_lock);
if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
kfree(elf_buf);
return -EFAULT;
@@ -352,7 +354,8 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
/* leave now if filled buffer already */
if (buflen == 0)
return acc;
- }
+ } else
+ read_unlock(&vmlist_lock);
/* where page 0 not mapped, write zeros into buffer */
#if defined (__i386__) || defined (__mc68000__)
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index 88d41c3c2..c64166f78 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -112,7 +112,6 @@ static void add_node(struct device_node *np, struct proc_dir_entry *de)
al = proc_symlink(at, de, ent->name);
if (al == 0)
break;
- proc_register(de, al);
*lastp = al;
lastp = &al->next;
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 8088d064d..075a5843d 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -22,38 +22,9 @@ struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver;
struct proc_dir_entry *proc_sys_root;
#endif
-/*
- * /proc/self:
- */
-static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
- char tmp[30];
- sprintf(tmp, "%d", current->pid);
- return vfs_readlink(dentry,buffer,buflen,tmp);
-}
-
-static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
- char tmp[30];
- sprintf(tmp, "%d", current->pid);
- return vfs_follow_link(nd,tmp);
-}
-
-static struct inode_operations proc_self_inode_operations = {
- readlink: proc_self_readlink,
- follow_link: proc_self_follow_link
-};
-
-static struct proc_dir_entry proc_root_self = {
- 0, 4, "self",
- S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
- 64, &proc_self_inode_operations,
-};
-
void __init proc_root_init(void)
{
proc_misc_init();
- proc_register(&proc_root, &proc_root_self);
proc_net = proc_mkdir("net", 0);
#ifdef CONFIG_SYSVIPC
proc_mkdir("sysvipc", 0);
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index 5be9b240f..3ef38467c 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -184,7 +184,6 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
mark_inode_dirty(dir);
- d_delete(dentry);
retval = 0;
end_rmdir:
@@ -228,7 +227,6 @@ int qnx4_unlink(struct inode *dir, struct dentry *dentry)
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
mark_inode_dirty(inode);
- d_delete(dentry);
retval = 0;
end_unlink:
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 75e94efd9..4416e8be6 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -227,7 +227,6 @@ static int ramfs_unlink(struct inode * dir, struct dentry *dentry)
inode->i_nlink--;
dput(dentry); /* Undo the count from "create" - this does all the work */
- d_delete(dentry);
retval = 0;
}
return retval;
@@ -269,57 +268,6 @@ static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char *
return error;
}
-/*
- * This really should be the same as the proc filldir,
- * once proc does the "one dentry tree" thing..
- */
-static int ramfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
-{
- int i;
- struct dentry *dentry = filp->f_dentry;
-
- i = filp->f_pos;
- switch (i) {
- case 0:
- if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino) < 0)
- break;
- i++;
- filp->f_pos++;
- /* fallthrough */
- case 1:
- if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino) < 0)
- break;
- i++;
- filp->f_pos++;
- /* fallthrough */
- default: {
- struct list_head *list = dentry->d_subdirs.next;
-
- int j = i-2;
- for (;;) {
- if (list == &dentry->d_subdirs)
- return 0;
- if (!j)
- break;
- j--;
- list = list->next;
- }
-
- do {
- struct dentry *de = list_entry(list, struct dentry, d_child);
-
- if (ramfs_positive(de)) {
- if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino) < 0)
- break;
- }
- filp->f_pos++;
- list = list->next;
- } while (list != &dentry->d_subdirs);
- }
- }
- return 0;
-}
-
static struct address_space_operations ramfs_aops = {
readpage: ramfs_readpage,
writepage: ramfs_writepage,
@@ -335,7 +283,7 @@ static struct file_operations ramfs_file_operations = {
static struct file_operations ramfs_dir_operations = {
read: generic_read_dir,
- readdir: ramfs_readdir,
+ readdir: dcache_readdir,
};
static struct inode_operations ramfs_dir_inode_operations = {
@@ -350,9 +298,15 @@ static struct inode_operations ramfs_dir_inode_operations = {
rename: ramfs_rename,
};
+static void ramfs_put_super(struct super_block *sb)
+{
+ d_genocide(sb->s_root);
+ shrink_dcache_parent(sb->s_root);
+}
static struct super_operations ramfs_ops = {
- statfs: ramfs_statfs,
+ put_super: ramfs_put_super,
+ statfs: ramfs_statfs,
};
static struct super_block *ramfs_read_super(struct super_block * sb, void * data, int silent)
diff --git a/fs/readdir.c b/fs/readdir.c
index e6256636e..059ab391d 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -32,6 +32,53 @@ out:
return res;
}
+int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+ int i;
+ struct dentry *dentry = filp->f_dentry;
+
+ i = filp->f_pos;
+ switch (i) {
+ case 0:
+ if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino) < 0)
+ break;
+ i++;
+ filp->f_pos++;
+ /* fallthrough */
+ case 1:
+ if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino) < 0)
+ break;
+ i++;
+ filp->f_pos++;
+ /* fallthrough */
+ default: {
+ struct list_head *list = dentry->d_subdirs.next;
+
+ int j = i-2;
+ for (;;) {
+ if (list == &dentry->d_subdirs)
+ return 0;
+ if (!j)
+ break;
+ j--;
+ list = list->next;
+ }
+
+ do {
+ struct dentry *de = list_entry(list, struct dentry, d_child);
+
+ if (!d_unhashed(de) && de->d_inode) {
+ if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino) < 0)
+ break;
+ }
+ filp->f_pos++;
+ list = list->next;
+ } while (list != &dentry->d_subdirs);
+ }
+ }
+ return 0;
+}
+
/*
* Traditional linux readdir() handling..
*
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index a29e55c7a..b5715b220 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -168,7 +168,7 @@ file->f_dentry->d_name.name);
static int smb_lookup_validate(struct dentry *, int);
static int smb_hash_dentry(struct dentry *, struct qstr *);
static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
-static void smb_delete_dentry(struct dentry *);
+static int smb_delete_dentry(struct dentry *);
static struct dentry_operations smbfs_dentry_operations =
{
@@ -259,9 +259,9 @@ out:
/*
* This is the callback from dput() when d_count is going to 0.
- * We use this to unhash dentries with bad inodes and close files.
+ * We use this to unhash dentries with bad inodes.
*/
-static void
+static int
smb_delete_dentry(struct dentry * dentry)
{
if (dentry->d_inode)
@@ -272,13 +272,13 @@ smb_delete_dentry(struct dentry * dentry)
printk("smb_delete_dentry: bad inode, unhashing %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
#endif
- d_drop(dentry);
+ return 1;
}
- smb_close_dentry(dentry);
} else
{
/* N.B. Unhash negative dentries? */
}
+ return 0;
}
/*
@@ -466,10 +466,7 @@ smb_unlink(struct inode *dir, struct dentry *dentry)
smb_invalid_dir_cache(dir);
error = smb_proc_unlink(dentry);
if (!error)
- {
smb_renew_times(dentry);
- d_delete(dentry);
- }
return error;
}
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 61f50bdff..b47e236b0 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -26,12 +26,6 @@
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
-static inline int
-min(int a, int b)
-{
- return a < b ? a : b;
-}
-
static int
smb_fsync(struct file *file, struct dentry * dentry)
{
@@ -340,28 +334,15 @@ out:
static int
smb_file_open(struct inode *inode, struct file * file)
{
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_file_open: opening %s/%s, d_count=%d\n",
-file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
-file->f_dentry->d_count);
-#endif
+ inode->u.smbfs_i.openers++;
return 0;
}
static int
smb_file_release(struct inode *inode, struct file * file)
{
- struct dentry * dentry = file->f_dentry;
-
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_file_release: closing %s/%s, d_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-#endif
-
- if (dentry->d_count == 1)
- {
+ if (!--inode->u.smbfs_i.openers)
smb_close(inode);
- }
return 0;
}
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index 06cd5dda9..669deb0d7 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -818,11 +818,6 @@ smb_open(struct dentry *dentry, int wish)
goto out;
}
- /*
- * Note: If the caller holds an active dentry and the file is
- * currently open, we can be sure that the file isn't about
- * to be closed. (See smb_close_dentry() below.)
- */
if (!smb_is_open(inode))
{
struct smb_sb_info *server = SMB_SERVER(inode);
@@ -944,46 +939,6 @@ smb_close(struct inode *ino)
}
/*
- * This routine is called from dput() when d_count is going to 0.
- * We use this to close the file so that cached dentries don't
- * keep too many files open.
- *
- * There are some tricky race conditions here: the dentry may go
- * back into use while we're closing the file, and we don't want
- * the new user to be confused as to the open status.
- */
-void
-smb_close_dentry(struct dentry * dentry)
-{
- struct inode *ino = dentry->d_inode;
-
- if (ino)
- {
- if (smb_is_open(ino))
- {
- struct smb_sb_info *server = SMB_SERVER(ino);
- smb_lock_server(server);
- /*
- * Check whether the dentry is back in use.
- */
- if (dentry->d_count <= 1)
- {
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_close_dentry: closing %s/%s, count=%d\n",
- DENTRY_PATH(dentry), dentry->d_count);
-#endif
- smb_proc_close_inode(server, ino);
- }
- smb_unlock_server(server);
- }
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_close_dentry: closed %s/%s, count=%d\n",
- DENTRY_PATH(dentry), dentry->d_count);
-#endif
- }
-}
-
-/*
* This is used to close a file following a failed instantiate.
* Since we don't have an inode, we can't use any of the above.
*/
diff --git a/fs/super.c b/fs/super.c
index b32b1fc6c..f1d873331 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -76,7 +76,7 @@ LIST_HEAD(super_blocks);
* Once the reference is obtained we can drop the spinlock.
*/
-static struct file_system_type *file_systems = NULL;
+static struct file_system_type *file_systems;
static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;
/* WARNING: This can be used only if we _already_ own a reference */
@@ -315,6 +315,7 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb,
strcpy(name, dir_name);
mnt->mnt_dirname = name;
}
+ mnt->mnt_owner = current->uid;
if (parent)
list_add(&mnt->mnt_child, &parent->mnt_mounts);
@@ -1020,10 +1021,6 @@ asmlinkage long sys_umount(char * name, int flags)
struct nameidata nd;
char *kname;
int retval;
- struct super_block *sb;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
lock_kernel();
kname = getname(name);
@@ -1036,10 +1033,14 @@ asmlinkage long sys_umount(char * name, int flags)
putname(kname);
if (retval)
goto out;
- sb = nd.dentry->d_inode->i_sb;
retval = -EINVAL;
if (nd.dentry!=nd.mnt->mnt_root)
goto dput_and_out;
+
+ retval = -EPERM;
+ if (!capable(CAP_SYS_ADMIN) && current->uid!=nd.mnt->mnt_owner)
+ goto dput_and_out;
+
dput(nd.dentry);
/* puts nd.mnt */
down(&mount_sem);
@@ -1062,6 +1063,21 @@ asmlinkage long sys_oldumount(char * name)
return sys_umount(name,0);
}
+static int mount_is_safe(struct nameidata *nd)
+{
+ if (capable(CAP_SYS_ADMIN))
+ return 0;
+ if (S_ISLNK(nd->dentry->d_inode->i_mode))
+ return -EPERM;
+ if (nd->dentry->d_inode->i_mode & S_ISVTX) {
+ if (current->uid != nd->dentry->d_inode->i_uid)
+ return -EPERM;
+ }
+ if (permission(nd->dentry->d_inode, MAY_WRITE))
+ return -EPERM;
+ return 0;
+}
+
/*
* do loopback mount.
*/
@@ -1071,18 +1087,22 @@ static int do_loopback(char *old_name, char *new_name)
int err = 0;
if (!old_name || !*old_name)
return -EINVAL;
- if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &old_nd))
+ if (path_init(old_name, LOOKUP_POSITIVE, &old_nd))
err = path_walk(old_name, &old_nd);
if (err)
goto out;
- if (path_init(new_name, LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &new_nd))
+ if (path_init(new_name, LOOKUP_POSITIVE, &new_nd))
err = path_walk(new_name, &new_nd);
if (err)
goto out1;
- err = -EPERM;
- if (!capable(CAP_SYS_ADMIN) &&
- current->uid != new_nd.dentry->d_inode->i_uid)
+ err = mount_is_safe(&new_nd);
+ if (err)
+ goto out2;
+ err = -EINVAL;
+ if (S_ISDIR(new_nd.dentry->d_inode->i_mode) !=
+ S_ISDIR(old_nd.dentry->d_inode->i_mode))
goto out2;
+
down(&mount_sem);
err = -ENOENT;
if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))
@@ -1143,31 +1163,29 @@ static int do_remount(const char *dir,int flags,char *data)
return retval;
}
-static int copy_mount_options (const void * data, unsigned long *where)
+static int copy_mount_options (const void *data, unsigned long *where)
{
int i;
unsigned long page;
- struct vm_area_struct * vma;
*where = 0;
if (!data)
return 0;
- vma = find_vma(current->mm, (unsigned long) data);
- if (!vma || (unsigned long) data < vma->vm_start)
- return -EFAULT;
- if (!(vma->vm_flags & VM_READ))
- return -EFAULT;
- i = vma->vm_end - (unsigned long) data;
- if (PAGE_SIZE <= (unsigned long) i)
- i = PAGE_SIZE-1;
- if (!(page = __get_free_page(GFP_KERNEL))) {
+ if (!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
- }
- if (copy_from_user((void *) page,data,i)) {
+
+ /* We only care that *some* data at the address the user
+ * gave us is valid. Just in case, we'll zero
+ * the remainder of the page.
+ */
+ i = copy_from_user((void *)page, data, PAGE_SIZE);
+ if (i == PAGE_SIZE) {
free_page(page);
return -EFAULT;
}
+ if (i)
+ memset((char *)page + PAGE_SIZE - i, 0, i);
*where = page;
return 0;
}
@@ -1186,7 +1204,7 @@ static int copy_mount_options (const void * data, unsigned long *where)
* aren't used, as the syscall assumes we are talking to an older
* version that didn't understand them.
*/
-long do_sys_mount(char * dev_name, char * dir_name, char *type_page,
+long do_mount(char * dev_name, char * dir_name, char *type_page,
unsigned long new_flags, void *data_page)
{
struct file_system_type * fstype;
@@ -1279,26 +1297,24 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void * data)
{
int retval;
- unsigned long data_page = 0;
- unsigned long type_page = 0;
- unsigned long dev_page = 0;
+ unsigned long data_page;
+ unsigned long type_page;
+ unsigned long dev_page;
char *dir_page;
- lock_kernel();
retval = copy_mount_options (type, &type_page);
if (retval < 0)
- goto out;
+ return retval;
/* copy_mount_options allows a NULL user pointer,
* and just returns zero in that case. But if we
* allow the type to be NULL we will crash.
* Previously we did not check this case.
*/
- if (type_page == 0) {
- retval = -EINVAL;
- goto out;
- }
+ if (type_page == 0)
+ return -EINVAL;
+ lock_kernel();
dir_page = getname(dir_name);
retval = PTR_ERR(dir_page);
if (IS_ERR(dir_page))
@@ -1309,7 +1325,7 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
goto out2;
retval = copy_mount_options (data, &data_page);
if (retval >= 0) {
- retval = do_sys_mount((char*)dev_page,dir_page,(char*)type_page,
+ retval = do_mount((char*)dev_page,dir_page,(char*)type_page,
new_flags, (void*)data_page);
free_page(data_page);
}
@@ -1318,7 +1334,6 @@ out2:
putname(dir_page);
out1:
free_page(type_page);
-out:
unlock_kernel();
return retval;
}
@@ -1493,10 +1508,6 @@ static void chroot_fs_refs(struct dentry *old_root,
{
struct task_struct *p;
- /* We can't afford dput() blocking under the tasklist_lock */
- mntget(old_rootmnt);
- dget(old_root);
-
read_lock(&tasklist_lock);
for_each_task(p) {
if (!p->fs) continue;
@@ -1506,9 +1517,6 @@ static void chroot_fs_refs(struct dentry *old_root,
set_fs_pwd(p->fs, new_rootmnt, new_root);
}
read_unlock(&tasklist_lock);
-
- dput(old_root);
- mntput(old_rootmnt);
}
/*
@@ -1525,8 +1533,8 @@ static void chroot_fs_refs(struct dentry *old_root,
asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
{
- struct dentry *root = current->fs->root;
- struct vfsmount *root_mnt = current->fs->rootmnt;
+ struct dentry *root;
+ struct vfsmount *root_mnt;
struct vfsmount *tmp;
struct nameidata new_nd, old_nd;
char *name;
@@ -1559,6 +1567,8 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
if (error)
goto out1;
+ root_mnt = mntget(current->fs->rootmnt);
+ root = dget(current->fs->root);
down(&mount_sem);
error = -ENOENT;
if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry))
@@ -1597,6 +1607,8 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
error = 0;
out2:
up(&mount_sem);
+ dput(root);
+ mntput(root_mnt);
path_release(&old_nd);
out1:
path_release(&new_nd);
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 0abffaac6..ef1e04381 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -398,7 +398,6 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
mark_inode_dirty(dir);
- d_delete(dentry);
retval = 0;
end_rmdir:
brelse(bh);
@@ -429,7 +428,6 @@ static int sysv_unlink(struct inode * dir, struct dentry * dentry)
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
mark_inode_dirty(inode);
- d_delete(dentry);
retval = 0;
end_unlink:
brelse(bh);
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index dcd980030..d56ff9a0c 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -346,7 +346,7 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
sb = dir->i_sb;
- if (dentry->d_name.len)
+ if (dentry)
{
if ( !(udf_char_to_ustr(&unifilename, dentry->d_name.name, dentry->d_name.len)) )
{
@@ -447,20 +447,17 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
}
}
- if (!lfi)
+ if (!lfi || !dentry)
continue;
- if ((flen = udf_get_filename(nameptr, fname, lfi)))
- {
- if (udf_match(flen, fname, &(dentry->d_name)))
- {
- if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- udf_release_data(bh);
- *err = -EEXIST;
- return NULL;
- }
+ if ((flen = udf_get_filename(nameptr, fname, lfi)) &&
+ udf_match(flen, fname, &(dentry->d_name))) {
+ if (fibh->sbh != fibh->ebh)
+ udf_release_data(fibh->ebh);
+ udf_release_data(fibh->sbh);
+ udf_release_data(bh);
+ *err = -EEXIST;
+ return NULL;
}
}
}
@@ -691,7 +688,6 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
struct udf_fileident_bh fibh;
int err;
struct FileIdentDesc cfi, *fi;
- struct dentry parent;
err = -EMLINK;
if (dir->i_nlink >= (256<<sizeof(dir->i_nlink))-1)
@@ -704,10 +700,8 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_op = &udf_dir_inode_operations;
inode->i_fop = &udf_dir_operations;
- parent.d_name.len = 0;
- parent.d_name.name = NULL;
inode->i_size = 0;
- if (!(fi = udf_add_entry(inode, &parent, &fibh, &cfi, &err)))
+ if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err)))
{
inode->i_nlink--;
mark_inode_dirty(inode);
@@ -852,7 +846,6 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry)
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
UDF_I_UCTIME(inode) = UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME;
mark_inode_dirty(dir);
- d_delete(dentry);
end_rmdir:
if (fibh.sbh != fibh.ebh)
@@ -902,7 +895,6 @@ static int udf_unlink(struct inode * dir, struct dentry * dentry)
mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime;
retval = 0;
- d_delete(dentry); /* This also frees the inode */
end_unlink:
if (fibh.sbh != fibh.ebh)
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index c60fcbcdb..2bd998cf3 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -673,7 +673,6 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
- d_delete(dentry);
end_rmdir:
brelse (bh);
@@ -730,7 +729,6 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry)
mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime;
retval = 0;
- d_delete(dentry); /* This also frees the inode */
end_unlink:
brelse (bh);
diff --git a/fs/umsdos/Makefile b/fs/umsdos/Makefile
index f1b7b3ed4..c14c1b615 100644
--- a/fs/umsdos/Makefile
+++ b/fs/umsdos/Makefile
@@ -8,7 +8,7 @@
# Note 2: the CFLAGS definitions are now in the main makefile.
O_TARGET := umsdos.o
-O_OBJS := dir.o inode.o ioctl.o mangle.o namei.o rdir.o emd.o check.o
+O_OBJS := dir.o inode.o ioctl.o mangle.o namei.o rdir.o emd.o
M_OBJS := $(O_TARGET)
diff --git a/fs/umsdos/check.c b/fs/umsdos/check.c
deleted file mode 100644
index 58755dd2c..000000000
--- a/fs/umsdos/check.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * linux/fs/umsdos/check.c
- *
- * Sanity-checking code
- */
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/umsdos_fs.h>
-
-#include <asm/system.h>
-
-#ifdef CHECK_PAGE_TABLES
-static int check_one_table (struct pde *page_dir)
-{
- if (pgd_none (*page_dir))
- return 0;
- if (pgd_bad (*page_dir))
- return 1;
- return 0;
-}
-
-/*
- * This function checks all page tables of "current"
- */
-void check_page_tables (void)
-{
- struct pgd *pg_dir;
- static int err = 0;
-
- int stack_level = (long) (&pg_dir) - current->kernel_stack_page;
-
- if (stack_level < 1500)
- printk ("** %d ** ", stack_level);
- pg_dir = PAGE_DIR_OFFSET (current, 0);
- if (err == 0) {
- int i;
-
- for (i = 0; i < PTRS_PER_PAGE; i++, page_dir++) {
- int notok = check_one_table (page_dir);
-
- if (notok) {
- err++;
- printk ("|%d:%08lx| ", i, page_dir->pgd);
- }
- }
- if (err)
- printk ("\nError MM %d\n", err);
- }
-}
-#endif
-
-
-#if UMS_DEBUG
-/*
- * check for wait queue in 2.3.x
- */
-inline void uq_log (char *txt, struct inode *inode)
-{
- printk (KERN_ERR "%s: (%lu) magic=%lu creator=%lu lock=%u\n", txt, inode->i_ino, inode->u.umsdos_i.dir_info.p.__magic, inode->u.umsdos_i.dir_info.p.__creator, inode->u.umsdos_i.dir_info.p.lock.lock);
-}
-
-/*
- * check a superblock
- */
-
-void check_sb (struct super_block *sb, const char c)
-{
- if (sb) {
- printk (" (has %c_sb=%d, %d)",
- c, MAJOR (sb->s_dev), MINOR (sb->s_dev));
- } else {
- printk (" (%c_sb is NULL)", c);
- }
-}
-
-/*
- * check an inode
- */
-
-void check_inode (struct inode *inode)
-{
- if (inode) {
- printk (KERN_DEBUG "* inode is %lu (i_count=%d)",
- inode->i_ino, inode->i_count);
- check_sb (inode->i_sb, 'i');
-
- if (inode->i_dentry.next) { /* FIXME: does this work ? */
- printk (" (has i_dentry)");
- } else {
- printk (" (NO i_dentry)");
- }
-
- printk (" (i_patched=%d)", inode->u.umsdos_i.i_patched);
-
- } else {
- printk (KERN_DEBUG "* inode is NULL\n");
- }
-}
-
-/*
- * checks all inode->i_dentry
- *
- */
-void checkd_inode (struct inode *inode)
-{
- struct dentry *ret;
- struct list_head *cur;
- int count = 0;
- if (!inode) {
- printk (KERN_ERR "checkd_inode: inode is NULL!\n");
- return;
- }
-
- printk (KERN_DEBUG "checkd_inode: inode %lu\n", inode->i_ino);
- cur = inode->i_dentry.next;
- while (count++ < 10) {
- PRINTK (("1..."));
- if (!cur) {
- printk (KERN_ERR "checkd_inode: *** NULL reached. exit.\n");
- return;
- }
- PRINTK (("2..."));
- ret = list_entry (cur, struct dentry, d_alias);
- PRINTK (("3..."));
- if (cur == cur->next) {
- printk (KERN_DEBUG "checkd_inode: *** cur=cur->next: normal exit.\n");
- return;
- }
- PRINTK (("4..."));
- if (!ret) {
- printk (KERN_ERR "checkd_inode: *** ret dentry is NULL. exit.\n");
- return;
- }
- PRINTK (("5... (ret=%p)...", ret));
- PRINTK (("5.1.. (ret->d_dname=%p)...", &(ret->d_name)));
- PRINTK (("5.1.1. (ret->d_dname.len=%d)...", (int) ret->d_name.len));
- PRINTK (("5.1.2. (ret->d_dname.name=%c)...", ret->d_name.name));
- printk (KERN_DEBUG "checkd_inode: i_dentry is %.*s\n", (int) ret->d_name.len, ret->d_name.name);
- PRINTK (("6..."));
- cur = cur->next;
- PRINTK (("7..."));
-#if 1
- printk (KERN_DEBUG "checkd_inode: *** finished after count 1 (operator forced)\n");
- return;
-#endif
- }
- printk (KERN_ERR "checkd_inode: *** OVER LIMIT (loop?) !\n");
- return;
-}
-
-/*
- * internal part of check_dentry. does the real job.
- *
- */
-
-void check_dent_int (struct dentry *dentry, int parent)
-{
- if (parent) {
- printk (KERN_DEBUG "* parent(%d) dentry: %.*s\n",
- parent, (int) dentry->d_name.len, dentry->d_name.name);
- } else {
- printk (KERN_DEBUG "* checking dentry: %.*s\n",
- (int) dentry->d_name.len, dentry->d_name.name);
- }
- check_inode (dentry->d_inode);
- printk (KERN_DEBUG "* d_count=%d", dentry->d_count);
- check_sb (dentry->d_sb, 'd');
- if (dentry->d_op == NULL) {
- printk (" (d_op is NULL)\n");
- } else {
- printk (" (d_op is UNKNOWN: %p)\n", dentry->d_op);
- }
-}
-
-/*
- * checks dentry with full traceback to root and prints info. Limited to 10 recursive depths to avoid infinite loops.
- *
- */
-
-void check_dentry_path (struct dentry *dentry, const char *desc)
-{
- int count=0;
- printk (KERN_DEBUG "*** check_dentry_path: %.60s\n", desc);
-
- if (!dentry) {
- printk (KERN_DEBUG "*** checking dentry... it is NULL !\n");
- return;
- }
- if (IS_ERR(dentry)) {
- printk (KERN_DEBUG "*** checking dentry... it is ERR(%ld) !\n",
- PTR_ERR(dentry));
- return;
- }
-
- while (dentry && count < 10) {
- check_dent_int (dentry, count++);
- if (IS_ROOT(dentry)) {
- printk (KERN_DEBUG "*** end checking dentry (root reached ok)\n");
- break;
- }
- dentry = dentry->d_parent;
- }
-
- if (count >= 10) { /* if infinite loop detected */
- printk (KERN_ERR
- "*** WARNING ! INFINITE LOOP ! check_dentry_path aborted !\n");
- }
-
- if (!dentry) {
- printk (KERN_ERR
- "*** WARNING ! NULL dentry ! check_dentry_path aborted !\n");
- }
-}
-#else
-inline void uq_log (char *txt, struct inode *inode) {};
-void check_sb (struct super_block *sb, const char c) {};
-void check_inode (struct inode *inode) {};
-void checkd_inode (struct inode *inode) {};
-void check_dentry_path (struct dentry *dentry, const char *desc) {};
-#endif /* UMS_DEBUG */
-
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 29eebb3f2..9d37f24bc 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -36,12 +36,14 @@ static int umsdos_dentry_validate(struct dentry *dentry, int flags)
}
/* for now, drop everything to force lookups ... */
-static void umsdos_dentry_dput(struct dentry *dentry)
+/* ITYM s/everything/& positive/... */
+static int umsdos_dentry_dput(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
if (inode) {
- d_drop(dentry);
+ return 1;
}
+ return 0;
}
struct dentry_operations umsdos_dentry_operations =
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 2e172e80b..af69877d9 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -367,14 +367,6 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
sb->s_root = new_root;
printk(KERN_INFO "UMSDOS: changed to alternate root\n");
}
-
- /* if d_count is not 1, mount will fail with -EBUSY! */
- if (sb->s_root->d_count > 1) {
- shrink_dcache_sb(sb);
- if (sb->s_root->d_count > 1) {
- printk(KERN_ERR "UMSDOS: root count %d > 1 !", sb->s_root->d_count);
- }
- }
return sb;
out_fail:
diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c
index 239043318..a8adf6ed8 100644
--- a/fs/umsdos/ioctl.c
+++ b/fs/umsdos/ioctl.c
@@ -331,6 +331,8 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
ret = -EISDIR;
if (!S_ISDIR(temp->d_inode->i_mode))
ret = msdos_unlink (dir, temp);
+ if (!ret)
+ d_delete(temp);
}
dput (temp);
goto out;
@@ -355,6 +357,8 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
ret = -ENOTDIR;
if (S_ISDIR(temp->d_inode->i_mode))
ret = msdos_rmdir (dir, temp);
+ if (!ret)
+ d_delete(temp);
}
dput (temp);
goto out;
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index 75715116f..d3fe5eb61 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -524,6 +524,7 @@ out_error:
out_unlink:
printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n");
UMSDOS_unlink (dir, dentry);
+ d_drop(dentry);
goto out;
}
@@ -898,9 +899,11 @@ if (err)
printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
demd->d_parent->d_name.name, demd->d_name.name, err);
#endif
- dput(demd);
- if (!err)
+ if (!err) {
+ d_delete(demd);
ret = 0;
+ }
+ dput(demd);
}
} else if (empty == 2)
ret = 0;
@@ -921,6 +924,7 @@ demd->d_parent->d_name.name, demd->d_name.name, err);
if (ret && ret != -ENOENT)
goto out_dput;
+ d_delete(temp);
/* OK so far ... remove the name from the EMD */
ret = umsdos_delentry (dentry->d_parent, &info, 1);
#ifdef UMSDOS_PARANOIA
@@ -1009,6 +1013,8 @@ Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
}
ret = msdos_unlink(dir, temp);
+ if (!ret)
+ d_delete(temp);
#ifdef UMSDOS_PARANOIA
if (ret)
printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
@@ -1018,8 +1024,6 @@ temp->d_parent->d_name.name, temp->d_name.name, ret);
/* dput() temp if we didn't do it above */
out_dput:
dput(temp);
- if (!ret)
- d_delete (dentry);
out_unlock:
umsdos_unlockcreate (dir);
@@ -1065,7 +1069,8 @@ link->d_parent->d_name.name, link->d_name.name, ret));
printk(KERN_WARNING
"umsdos_unlink: link removal failed, ret=%d\n",
ret);
- }
+ } else
+ d_delete(link);
} else {
struct iattr newattrs;
inode->i_nlink--;
@@ -1100,11 +1105,13 @@ int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
* If the target already exists, delete it first.
*/
if (new_dentry->d_inode) {
- new_dentry->d_count++;
+ dget(new_dentry);
if (S_ISDIR(old_dentry->d_inode->i_mode))
ret = UMSDOS_rmdir (new_dir, new_dentry);
else
ret = UMSDOS_unlink (new_dir, new_dentry);
+ if (!ret)
+ d_drop(new_dentry);
dput(new_dentry);
if (ret)
return ret;
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index 8c71dd727..a477ade2c 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -174,6 +174,8 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
ret = 0;
if (demd->d_inode)
ret = msdos_unlink (dentry->d_inode, demd);
+ if (!ret)
+ d_delete(demd);
dput(demd);
}
}
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index ceb67870d..0439d63fc 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -961,24 +961,6 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
return res ? res : -ENOENT;
}
-/* Find a hashed dentry for inode; NULL if there are none */
-static struct dentry *find_alias(struct inode *inode)
-{
- struct list_head *head, *next, *tmp;
- struct dentry *alias;
-
- head = &inode->i_dentry;
- next = inode->i_dentry.next;
- while (next != head) {
- tmp = next;
- next = tmp->next;
- alias = list_entry(tmp, struct dentry, d_alias);
- if (!d_unhashed(alias))
- return dget(alias);
- }
- return NULL;
-}
-
struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry)
{
int res;
@@ -1005,7 +987,7 @@ struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry)
fat_brelse(dir->i_sb, bh);
if (res)
return ERR_PTR(res);
- alias = find_alias(inode);
+ alias = d_find_alias(inode);
if (alias) {
if (d_invalidate(alias)==0)
dput(alias);
@@ -1116,7 +1098,6 @@ int vfat_unlink(struct inode *dir, struct dentry* dentry)
mark_inode_dirty(dentry->d_inode);
/* releases bh */
vfat_remove_entry(dir,&sinfo,bh,de);
- d_delete(dentry);
return res;
}