diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /fs/namei.c | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff) |
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too
o Upgrade to 2.1.89.
Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 113 |
1 files changed, 57 insertions, 56 deletions
diff --git a/fs/namei.c b/fs/namei.c index ab8d6089e..519a8ceac 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -221,51 +221,39 @@ void put_write_access(struct inode * inode) } /* - * This is called when everything else fails, and we actually have - * to go to the low-level filesystem to find out what we should do.. - * - * We get the directory semaphore, and after getting that we also - * make sure that nobody added the entry to the dcache in the meantime.. + * "." and ".." are special - ".." especially so because it has to be able + * to know about the current root directory and parent relationships */ -static struct dentry * real_lookup(struct dentry * parent, struct qstr * name) +static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * name) { - struct dentry * result; - struct inode *dir = parent->d_inode; + struct dentry *result = NULL; + if (name->name[0] == '.') { + switch (name->len) { + default: + break; + case 2: + if (name->name[1] != '.') + break; - down(&dir->i_sem); - result = d_lookup(parent, name); - if (!result) { - struct dentry * dentry = d_alloc(parent, name); - result = ERR_PTR(-ENOMEM); - if (dentry) { - int error = dir->i_op->lookup(dir, dentry); - result = dentry; - if (error) { - dput(dentry); - result = ERR_PTR(error); - } + if (parent != current->fs->root) + parent = parent->d_covers->d_parent; + /* fallthrough */ + case 1: + result = parent; } } - up(&dir->i_sem); - return result; + return dget(result); } /* * Internal lookup() using the new generic dcache. - * - * Note the revalidation: we have to drop the dcache - * lock when we revalidate, so we need to update the - * counts around it. */ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name) { struct dentry * dentry = d_lookup(parent, name); if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { - int validated, (*revalidate)(struct dentry *) = dentry->d_op->d_revalidate; - - validated = revalidate(dentry) || d_invalidate(dentry); - if (!validated) { + if (!dentry->d_op->d_revalidate(dentry) && !d_invalidate(dentry)) { dput(dentry); dentry = NULL; } @@ -274,28 +262,40 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name) } /* - * "." and ".." are special - ".." especially so because it has to be able - * to know about the current root directory and parent relationships + * This is called when everything else fails, and we actually have + * to go to the low-level filesystem to find out what we should do.. + * + * We get the directory semaphore, and after getting that we also + * make sure that nobody added the entry to the dcache in the meantime.. */ -static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * name) +static struct dentry * real_lookup(struct dentry * parent, struct qstr * name) { - struct dentry *result = NULL; - if (name->name[0] == '.') { - switch (name->len) { - default: - break; - case 2: - if (name->name[1] != '.') - break; + struct dentry * result; + struct inode *dir = parent->d_inode; - if (parent != current->fs->root) - parent = parent->d_covers->d_parent; - /* fallthrough */ - case 1: - result = parent; + down(&dir->i_sem); + /* + * First re-do the cached lookup just in case it was created + * while we waited for the directory semaphore.. + * + * FIXME! This could use version numbering or similar to + * avoid unnecessary cache lookups. + */ + result = cached_lookup(parent, name); + if (!result) { + struct dentry * dentry = d_alloc(parent, name); + result = ERR_PTR(-ENOMEM); + if (dentry) { + int error = dir->i_op->lookup(dir, dentry); + result = dentry; + if (error) { + dput(dentry); + result = ERR_PTR(error); + } } } - return dget(result); + up(&dir->i_sem); + return result; } static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry) @@ -308,7 +308,7 @@ static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry current->link_count++; /* This eats the base */ - result = inode->i_op->follow_link(inode, base); + result = inode->i_op->follow_link(dentry, base); current->link_count--; dput(dentry); return result; @@ -358,7 +358,7 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, int follo /* At this point we know we have a real path component. */ for(;;) { - int len, err; + int err; unsigned long hash; struct qstr this; struct inode *inode; @@ -379,16 +379,14 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, int follo break; this.name = name; - len = 0; c = *name; hash = init_name_hash(); do { - len++; name++; hash = partial_name_hash(c, hash); - c = *name; + c = *++name; } while (c && (c != '/')); - this.len = len; + this.len = name - (const char *) this.name; this.hash = end_name_hash(hash); /* remove trailing slashes? */ @@ -632,7 +630,7 @@ struct dentry * open_namei(const char * pathname, int flag, int mode) if (inode->i_sb && inode->i_sb->dq_op) inode->i_sb->dq_op->initialize(inode, -1); - error = do_truncate(inode, 0); + error = do_truncate(dentry, 0); } put_write_access(inode); if (error) @@ -833,7 +831,7 @@ static inline int do_rmdir(const char * name) /* Disallow removals of mountpoints. */ error = -EBUSY; - if (dentry == dir) + if (dentry->d_mounts != dentry->d_covers) goto exit_lock; error = -EPERM; @@ -843,6 +841,9 @@ static inline int do_rmdir(const char * name) if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op) dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1); + if (dentry->d_count > 1) + shrink_dcache_parent(dentry); + error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry); exit_lock: @@ -1073,7 +1074,7 @@ static inline int do_link(const char * oldname, const char * newname) if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op) dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1); - error = dir->d_inode->i_op->link(inode, dir->d_inode, new_dentry); + error = dir->d_inode->i_op->link(old_dentry, dir->d_inode, new_dentry); exit_lock: unlock_dir(dir); |