Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git

This commit is contained in:
Steve French
2005-06-09 14:44:56 -07:00
104 changed files with 1361 additions and 641 deletions

View File

@@ -520,7 +520,7 @@ static int load_flat_file(struct linux_binprm * bprm,
DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
down_write(&current->mm->mmap_sem);
textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, 0, 0);
textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_SHARED, 0);
up_write(&current->mm->mmap_sem);
if (!textpos || textpos >= (unsigned long) -4096) {
if (!textpos)
@@ -532,7 +532,7 @@ static int load_flat_file(struct linux_binprm * bprm,
down_write(&current->mm->mmap_sem);
realdatastart = do_mmap(0, 0, data_len + extra +
MAX_SHARED_LIBS * sizeof(unsigned long),
PROT_READ|PROT_WRITE|PROT_EXEC, 0, 0);
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
up_write(&current->mm->mmap_sem);
if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) {
@@ -574,7 +574,7 @@ static int load_flat_file(struct linux_binprm * bprm,
down_write(&current->mm->mmap_sem);
textpos = do_mmap(0, 0, text_len + data_len + extra +
MAX_SHARED_LIBS * sizeof(unsigned long),
PROT_READ | PROT_EXEC | PROT_WRITE, 0, 0);
PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
up_write(&current->mm->mmap_sem);
if (!textpos || textpos >= (unsigned long) -4096) {
if (!textpos)

View File

@@ -493,12 +493,21 @@ fail:
return PTR_ERR(link);
}
static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd)
struct path {
struct vfsmount *mnt;
struct dentry *dentry;
};
static inline int __do_follow_link(struct path *path, struct nameidata *nd)
{
int error;
struct dentry *dentry = path->dentry;
touch_atime(nd->mnt, dentry);
touch_atime(path->mnt, dentry);
nd_set_link(nd, NULL);
if (path->mnt == nd->mnt)
mntget(path->mnt);
error = dentry->d_inode->i_op->follow_link(dentry, nd);
if (!error) {
char *s = nd_get_link(nd);
@@ -507,6 +516,8 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd)
if (dentry->d_inode->i_op->put_link)
dentry->d_inode->i_op->put_link(dentry, nd);
}
dput(dentry);
mntput(path->mnt);
return error;
}
@@ -518,7 +529,7 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd)
* Without that kind of total limit, nasty chains of consecutive
* symlinks can cause almost arbitrarily long lookups.
*/
static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
static inline int do_follow_link(struct path *path, struct nameidata *nd)
{
int err = -ELOOP;
if (current->link_count >= MAX_NESTED_LINKS)
@@ -527,17 +538,20 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
goto loop;
BUG_ON(nd->depth >= MAX_NESTED_LINKS);
cond_resched();
err = security_inode_follow_link(dentry, nd);
err = security_inode_follow_link(path->dentry, nd);
if (err)
goto loop;
current->link_count++;
current->total_link_count++;
nd->depth++;
err = __do_follow_link(dentry, nd);
err = __do_follow_link(path, nd);
current->link_count--;
nd->depth--;
return err;
loop:
dput(path->dentry);
if (path->mnt != nd->mnt)
mntput(path->mnt);
path_release(nd);
return err;
}
@@ -565,87 +579,91 @@ int follow_up(struct vfsmount **mnt, struct dentry **dentry)
/* no need for dcache_lock, as serialization is taken care in
* namespace.c
*/
static int follow_mount(struct vfsmount **mnt, struct dentry **dentry)
static int __follow_mount(struct path *path)
{
int res = 0;
while (d_mountpoint(*dentry)) {
struct vfsmount *mounted = lookup_mnt(*mnt, *dentry);
while (d_mountpoint(path->dentry)) {
struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry);
if (!mounted)
break;
mntput(*mnt);
*mnt = mounted;
dput(*dentry);
*dentry = dget(mounted->mnt_root);
dput(path->dentry);
if (res)
mntput(path->mnt);
path->mnt = mounted;
path->dentry = dget(mounted->mnt_root);
res = 1;
}
return res;
}
static void follow_mount(struct vfsmount **mnt, struct dentry **dentry)
{
while (d_mountpoint(*dentry)) {
struct vfsmount *mounted = lookup_mnt(*mnt, *dentry);
if (!mounted)
break;
dput(*dentry);
mntput(*mnt);
*mnt = mounted;
*dentry = dget(mounted->mnt_root);
}
}
/* no need for dcache_lock, as serialization is taken care in
* namespace.c
*/
static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
int follow_down(struct vfsmount **mnt, struct dentry **dentry)
{
struct vfsmount *mounted;
mounted = lookup_mnt(*mnt, *dentry);
if (mounted) {
dput(*dentry);
mntput(*mnt);
*mnt = mounted;
dput(*dentry);
*dentry = dget(mounted->mnt_root);
return 1;
}
return 0;
}
int follow_down(struct vfsmount **mnt, struct dentry **dentry)
{
return __follow_down(mnt,dentry);
}
static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry)
static inline void follow_dotdot(struct nameidata *nd)
{
while(1) {
struct vfsmount *parent;
struct dentry *old = *dentry;
struct dentry *old = nd->dentry;
read_lock(&current->fs->lock);
if (*dentry == current->fs->root &&
*mnt == current->fs->rootmnt) {
if (nd->dentry == current->fs->root &&
nd->mnt == current->fs->rootmnt) {
read_unlock(&current->fs->lock);
break;
}
read_unlock(&current->fs->lock);
spin_lock(&dcache_lock);
if (*dentry != (*mnt)->mnt_root) {
*dentry = dget((*dentry)->d_parent);
if (nd->dentry != nd->mnt->mnt_root) {
nd->dentry = dget(nd->dentry->d_parent);
spin_unlock(&dcache_lock);
dput(old);
break;
}
spin_unlock(&dcache_lock);
spin_lock(&vfsmount_lock);
parent = (*mnt)->mnt_parent;
if (parent == *mnt) {
parent = nd->mnt->mnt_parent;
if (parent == nd->mnt) {
spin_unlock(&vfsmount_lock);
break;
}
mntget(parent);
*dentry = dget((*mnt)->mnt_mountpoint);
nd->dentry = dget(nd->mnt->mnt_mountpoint);
spin_unlock(&vfsmount_lock);
dput(old);
mntput(*mnt);
*mnt = parent;
mntput(nd->mnt);
nd->mnt = parent;
}
follow_mount(mnt, dentry);
follow_mount(&nd->mnt, &nd->dentry);
}
struct path {
struct vfsmount *mnt;
struct dentry *dentry;
};
/*
* It's more convoluted than I'd like it to be, but... it's still fairly
* small and for now I'd prefer to have fast path as straight as possible.
@@ -664,6 +682,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
done:
path->mnt = mnt;
path->dentry = dentry;
__follow_mount(path);
return 0;
need_lookup:
@@ -751,7 +770,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
case 2:
if (this.name[1] != '.')
break;
follow_dotdot(&nd->mnt, &nd->dentry);
follow_dotdot(nd);
inode = nd->dentry->d_inode;
/* fallthrough */
case 1:
@@ -771,8 +790,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
err = do_lookup(nd, &this, &next);
if (err)
break;
/* Check mountpoints.. */
follow_mount(&next.mnt, &next.dentry);
err = -ENOENT;
inode = next.dentry->d_inode;
@@ -783,10 +800,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
goto out_dput;
if (inode->i_op->follow_link) {
mntget(next.mnt);
err = do_follow_link(next.dentry, nd);
dput(next.dentry);
mntput(next.mnt);
err = do_follow_link(&next, nd);
if (err)
goto return_err;
err = -ENOENT;
@@ -798,6 +812,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
break;
} else {
dput(nd->dentry);
if (nd->mnt != next.mnt)
mntput(nd->mnt);
nd->mnt = next.mnt;
nd->dentry = next.dentry;
}
@@ -819,7 +835,7 @@ last_component:
case 2:
if (this.name[1] != '.')
break;
follow_dotdot(&nd->mnt, &nd->dentry);
follow_dotdot(nd);
inode = nd->dentry->d_inode;
/* fallthrough */
case 1:
@@ -833,19 +849,17 @@ last_component:
err = do_lookup(nd, &this, &next);
if (err)
break;
follow_mount(&next.mnt, &next.dentry);
inode = next.dentry->d_inode;
if ((lookup_flags & LOOKUP_FOLLOW)
&& inode && inode->i_op && inode->i_op->follow_link) {
mntget(next.mnt);
err = do_follow_link(next.dentry, nd);
dput(next.dentry);
mntput(next.mnt);
err = do_follow_link(&next, nd);
if (err)
goto return_err;
inode = nd->dentry->d_inode;
} else {
dput(nd->dentry);
if (nd->mnt != next.mnt)
mntput(nd->mnt);
nd->mnt = next.mnt;
nd->dentry = next.dentry;
}
@@ -885,6 +899,8 @@ return_base:
return 0;
out_dput:
dput(next.dentry);
if (nd->mnt != next.mnt)
mntput(next.mnt);
break;
}
path_release(nd);
@@ -1398,7 +1414,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
{
int acc_mode, error = 0;
struct dentry *dentry;
struct path path;
struct dentry *dir;
int count = 0;
@@ -1442,23 +1458,24 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
dir = nd->dentry;
nd->flags &= ~LOOKUP_PARENT;
down(&dir->d_inode->i_sem);
dentry = __lookup_hash(&nd->last, nd->dentry, nd);
path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
path.mnt = nd->mnt;
do_last:
error = PTR_ERR(dentry);
if (IS_ERR(dentry)) {
error = PTR_ERR(path.dentry);
if (IS_ERR(path.dentry)) {
up(&dir->d_inode->i_sem);
goto exit;
}
/* Negative dentry, just create the file */
if (!dentry->d_inode) {
if (!path.dentry->d_inode) {
if (!IS_POSIXACL(dir->d_inode))
mode &= ~current->fs->umask;
error = vfs_create(dir->d_inode, dentry, mode, nd);
error = vfs_create(dir->d_inode, path.dentry, mode, nd);
up(&dir->d_inode->i_sem);
dput(nd->dentry);
nd->dentry = dentry;
nd->dentry = path.dentry;
if (error)
goto exit;
/* Don't check for write permission, don't truncate */
@@ -1476,22 +1493,24 @@ do_last:
if (flag & O_EXCL)
goto exit_dput;
if (d_mountpoint(dentry)) {
if (__follow_mount(&path)) {
error = -ELOOP;
if (flag & O_NOFOLLOW)
goto exit_dput;
while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));
}
error = -ENOENT;
if (!dentry->d_inode)
if (!path.dentry->d_inode)
goto exit_dput;
if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link)
if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link)
goto do_link;
dput(nd->dentry);
nd->dentry = dentry;
nd->dentry = path.dentry;
if (nd->mnt != path.mnt)
mntput(nd->mnt);
nd->mnt = path.mnt;
error = -EISDIR;
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))
goto exit;
ok:
error = may_open(nd, acc_mode, flag);
@@ -1500,7 +1519,9 @@ ok:
return 0;
exit_dput:
dput(dentry);
dput(path.dentry);
if (nd->mnt != path.mnt)
mntput(path.mnt);
exit:
path_release(nd);
return error;
@@ -1520,18 +1541,15 @@ do_link:
* are done. Procfs-like symlinks just set LAST_BIND.
*/
nd->flags |= LOOKUP_PARENT;
error = security_inode_follow_link(dentry, nd);
error = security_inode_follow_link(path.dentry, nd);
if (error)
goto exit_dput;
error = __do_follow_link(dentry, nd);
dput(dentry);
error = __do_follow_link(&path, nd);
if (error)
return error;
nd->flags &= ~LOOKUP_PARENT;
if (nd->last_type == LAST_BIND) {
dentry = nd->dentry;
if (nd->last_type == LAST_BIND)
goto ok;
}
error = -EISDIR;
if (nd->last_type != LAST_NORM)
goto exit;
@@ -1546,7 +1564,8 @@ do_link:
}
dir = nd->dentry;
down(&dir->d_inode->i_sem);
dentry = __lookup_hash(&nd->last, nd->dentry, nd);
path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
path.mnt = nd->mnt;
putname(nd->last.name);
goto do_last;
}

View File

@@ -528,19 +528,39 @@ static inline void nfs_renew_times(struct dentry * dentry)
dentry->d_time = jiffies;
}
/*
* Return the intent data that applies to this particular path component
*
* Note that the current set of intents only apply to the very last
* component of the path.
* We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT.
*/
static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask)
{
if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))
return 0;
return nd->flags & mask;
}
/*
* Inode and filehandle revalidation for lookups.
*
* We force revalidation in the cases where the VFS sets LOOKUP_REVAL,
* or if the intent information indicates that we're about to open this
* particular file and the "nocto" mount flag is not set.
*
*/
static inline
int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
{
struct nfs_server *server = NFS_SERVER(inode);
if (nd != NULL) {
int ndflags = nd->flags;
/* VFS wants an on-the-wire revalidation */
if (ndflags & LOOKUP_REVAL)
if (nd->flags & LOOKUP_REVAL)
goto out_force;
/* This is an open(2) */
if ((ndflags & LOOKUP_OPEN) &&
!(ndflags & LOOKUP_CONTINUE) &&
if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
!(server->flags & NFS_MOUNT_NOCTO))
goto out_force;
}
@@ -560,12 +580,8 @@ static inline
int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
int ndflags = 0;
if (nd)
ndflags = nd->flags;
/* Don't revalidate a negative dentry if we're creating a new file */
if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE))
if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0)
return 0;
return !nfs_check_verifier(dir, dentry);
}
@@ -700,12 +716,16 @@ struct dentry_operations nfs_dentry_operations = {
.d_iput = nfs_dentry_iput,
};
/*
* Use intent information to check whether or not we're going to do
* an O_EXCL create using this path component.
*/
static inline
int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
{
if (NFS_PROTO(dir)->version == 2)
return 0;
if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE))
if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
return 0;
return (nd->intent.open.flags & O_EXCL) != 0;
}
@@ -772,12 +792,13 @@ struct dentry_operations nfs4_dentry_operations = {
.d_iput = nfs_dentry_iput,
};
/*
* Use intent information to determine whether we need to substitute
* the NFSv4-style stateful OPEN for the LOOKUP call
*/
static int is_atomic_open(struct inode *dir, struct nameidata *nd)
{
if (!nd)
return 0;
/* Check that we are indeed trying to open this file */
if ((nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_OPEN))
if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0)
return 0;
/* NFS does not (yet) have a stateful open for directories */
if (nd->flags & LOOKUP_DIRECTORY)