aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/alpha/kernel/osf_sys.c7
-rw-r--r--arch/parisc/hpux/fs.c5
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c4
-rw-r--r--drivers/md/dm-table.c21
-rw-r--r--fs/Kconfig7
-rw-r--r--fs/afs/dir.c1
-rw-r--r--fs/attr.c10
-rw-r--r--fs/bfs/dir.c1
-rw-r--r--fs/block_dev.c14
-rw-r--r--fs/char_dev.c21
-rw-r--r--fs/cifs/cifsfs.c10
-rw-r--r--fs/coda/dir.c3
-rw-r--r--fs/coda/pioctl.c2
-rw-r--r--fs/compat.c22
-rw-r--r--fs/configfs/symlink.c16
-rw-r--r--fs/dcache.c184
-rw-r--r--fs/dquot.c10
-rw-r--r--fs/ecryptfs/main.c23
-rw-r--r--fs/efs/namei.c29
-rw-r--r--fs/exportfs/expfs.c20
-rw-r--r--fs/ext2/dir.c14
-rw-r--r--fs/ext2/ext2.h4
-rw-r--r--fs/ext2/namei.c30
-rw-r--r--fs/ext3/namei.c84
-rw-r--r--fs/ext3/super.c22
-rw-r--r--fs/ext4/namei.c11
-rw-r--r--fs/ext4/super.c24
-rw-r--r--fs/fat/dir.c1
-rw-r--r--fs/fat/inode.c52
-rw-r--r--fs/fuse/inode.c23
-rw-r--r--fs/gfs2/ops_export.c33
-rw-r--r--fs/gfs2/ops_inode.c2
-rw-r--r--fs/hfs/inode.c8
-rw-r--r--fs/hfsplus/inode.c13
-rw-r--r--fs/hpfs/file.c2
-rw-r--r--fs/hpfs/hpfs_fn.h2
-rw-r--r--fs/hpfs/inode.c29
-rw-r--r--fs/hpfs/namei.c2
-rw-r--r--fs/isofs/export.c33
-rw-r--r--fs/jffs2/dir.c7
-rw-r--r--fs/jffs2/super.c48
-rw-r--r--fs/jfs/namei.c16
-rw-r--r--fs/libfs.c26
-rw-r--r--fs/namei.c146
-rw-r--r--fs/namespace.c133
-rw-r--r--fs/nfs/dir.c9
-rw-r--r--fs/nfs/getroot.c14
-rw-r--r--fs/nfsd/export.c125
-rw-r--r--fs/nfsd/nfs4recover.c50
-rw-r--r--fs/nfsd/nfs4state.c8
-rw-r--r--fs/nfsd/nfsctl.c8
-rw-r--r--fs/nfsd/vfs.c126
-rw-r--r--fs/ntfs/namei.c22
-rw-r--r--fs/ocfs2/export.c30
-rw-r--r--fs/omfs/dir.c1
-rw-r--r--fs/openpromfs/inode.c1
-rw-r--r--fs/proc/proc_sysctl.c11
-rw-r--r--fs/read_write.c58
-rw-r--r--fs/readdir.c22
-rw-r--r--fs/reiserfs/file.c1
-rw-r--r--fs/reiserfs/inode.c13
-rw-r--r--fs/reiserfs/namei.c11
-rw-r--r--fs/reiserfs/super.c18
-rw-r--r--fs/super.c15
-rw-r--r--fs/sysfs/dir.c1
-rw-r--r--fs/udf/namei.c43
-rw-r--r--fs/ufs/dir.c1
-rw-r--r--fs/xfs/linux-2.6/xfs_export.c32
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c128
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c7
-rw-r--r--include/linux/dcache.h3
-rw-r--r--include/linux/fs.h8
-rw-r--r--include/linux/namei.h8
-rw-r--r--init/main.c1
-rw-r--r--kernel/audit_tree.c48
-rw-r--r--net/unix/af_unix.c18
76 files changed, 883 insertions, 1133 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 8509dad3120..f25f6c49095 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -165,14 +165,11 @@ osf_getdirentries(unsigned int fd, struct osf_dirent __user *dirent,
buf.error = 0;
error = vfs_readdir(file, osf_filldir, &buf);
- if (error < 0)
- goto out_putf;
-
- error = buf.error;
+ if (error >= 0)
+ error = buf.error;
if (count != buf.count)
error = count - buf.count;
- out_putf:
fput(file);
out:
return error;
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index 12c04c5e558..bd9a4db3bd4 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -127,9 +127,8 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
buf.error = 0;
error = vfs_readdir(file, filldir, &buf);
- if (error < 0)
- goto out_putf;
- error = buf.error;
+ if (error >= 0)
+ error = buf.error;
lastdirent = buf.previous;
if (lastdirent) {
if (put_user(file->f_pos, &lastdirent->d_off))
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index 49c87769b1f..c23617c6baf 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -69,9 +69,9 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
if (!IS_ERR(tmp)) {
struct nameidata nd;
- ret = path_lookup(tmp, LOOKUP_PARENT|
- LOOKUP_OPEN|LOOKUP_CREATE, &nd);
+ ret = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (!ret) {
+ nd.flags |= LOOKUP_OPEN | LOOKUP_CREATE;
ret = spufs_create(&nd, flags, mode, neighbor);
path_put(&nd.path);
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index a740a6950f5..1407eb96f1a 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -313,19 +313,6 @@ static inline int check_space(struct dm_table *t)
}
/*
- * Convert a device path to a dev_t.
- */
-static int lookup_device(const char *path, dev_t *dev)
-{
- struct block_device *bdev = lookup_bdev(path);
- if (IS_ERR(bdev))
- return PTR_ERR(bdev);
- *dev = bdev->bd_dev;
- bdput(bdev);
- return 0;
-}
-
-/*
* See if we've already got a device in the list.
*/
static struct dm_dev_internal *find_device(struct list_head *l, dev_t dev)
@@ -437,8 +424,12 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
return -EOVERFLOW;
} else {
/* convert the path to a device */
- if ((r = lookup_device(path, &dev)))
- return r;
+ struct block_device *bdev = lookup_bdev(path);
+
+ if (IS_ERR(bdev))
+ return PTR_ERR(bdev);
+ dev = bdev->bd_dev;
+ bdput(bdev);
}
dd = find_device(&t->devices, dev);
diff --git a/fs/Kconfig b/fs/Kconfig
index e46297f020c..522469a7eca 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -22,9 +22,10 @@ source "fs/jbd2/Kconfig"
config FS_MBCACHE
# Meta block cache for Extended Attributes (ext2/ext3/ext4)
tristate
- depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR
- default y if EXT2_FS=y || EXT3_FS=y || EXT4_FS=y
- default m if EXT2_FS=m || EXT3_FS=m || EXT4_FS=m
+ default y if EXT2_FS=y && EXT2_FS_XATTR
+ default y if EXT3_FS=y && EXT3_FS_XATTR
+ default y if EXT4_FS=y && EXT4_FS_XATTR
+ default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR
config REISERFS_FS
tristate "Reiserfs support"
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index dfda03d4397..99cf390641f 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -45,6 +45,7 @@ const struct file_operations afs_dir_file_operations = {
.release = afs_release,
.readdir = afs_readdir,
.lock = afs_lock,
+ .llseek = generic_file_llseek,
};
const struct inode_operations afs_dir_inode_operations = {
diff --git a/fs/attr.c b/fs/attr.c
index 26c71ba1eed..7a83819f6ba 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -159,17 +159,17 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
return 0;
+ error = security_inode_setattr(dentry, attr);
+ if (error)
+ return error;
+
if (ia_valid & ATTR_SIZE)
down_write(&dentry->d_inode->i_alloc_sem);
if (inode->i_op && inode->i_op->setattr) {
- error = security_inode_setattr(dentry, attr);
- if (!error)
- error = inode->i_op->setattr(dentry, attr);
+ error = inode->i_op->setattr(dentry, attr);
} else {
error = inode_change_ok(inode, attr);
- if (!error)
- error = security_inode_setattr(dentry, attr);
if (!error) {
if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index ed8feb052df..daae463068e 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -80,6 +80,7 @@ const struct file_operations bfs_dir_operations = {
.read = generic_read_dir,
.readdir = bfs_readdir,
.fsync = file_fsync,
+ .llseek = generic_file_llseek,
};
extern void dump_imap(const char *, struct super_block *);
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 218408eed1b..d06fe3c3dd3 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1268,33 +1268,33 @@ EXPORT_SYMBOL(ioctl_by_bdev);
* namespace if possible and return it. Return ERR_PTR(error)
* otherwise.
*/
-struct block_device *lookup_bdev(const char *path)
+struct block_device *lookup_bdev(const char *pathname)
{
struct block_device *bdev;
struct inode *inode;
- struct nameidata nd;
+ struct path path;
int error;
- if (!path || !*path)
+ if (!pathname || !*pathname)
return ERR_PTR(-EINVAL);
- error = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ error = kern_path(pathname, LOOKUP_FOLLOW, &path);
if (error)
return ERR_PTR(error);
- inode = nd.path.dentry->d_inode;
+ inode = path.dentry->d_inode;
error = -ENOTBLK;
if (!S_ISBLK(inode->i_mode))
goto fail;
error = -EACCES;
- if (nd.path.mnt->mnt_flags & MNT_NODEV)
+ if (path.mnt->mnt_flags & MNT_NODEV)
goto fail;
error = -ENOMEM;
bdev = bd_acquire(inode);
if (!bdev)
goto fail;
out:
- path_put(&nd.path);
+ path_put(&path);
return bdev;
fail:
bdev = ERR_PTR(error);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 262fa10e213..700697a7261 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -386,15 +386,22 @@ static int chrdev_open(struct inode *inode, struct file *filp)
cdev_put(new);
if (ret)
return ret;
+
+ ret = -ENXIO;
filp->f_op = fops_get(p->ops);
- if (!filp->f_op) {
- cdev_put(p);
- return -ENXIO;
- }
- if (filp->f_op->open)
+ if (!filp->f_op)
+ goto out_cdev_put;
+
+ if (filp->f_op->open) {
ret = filp->f_op->open(inode,filp);
- if (ret)
- cdev_put(p);
+ if (ret)
+ goto out_cdev_put;
+ }
+
+ return 0;
+
+ out_cdev_put:
+ cdev_put(p);
return ret;
}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 25ecbd5b040..84cc011a16e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -275,9 +275,12 @@ static int cifs_permission(struct inode *inode, int mask)
cifs_sb = CIFS_SB(inode->i_sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
- return 0;
- else /* file mode might have been restricted at mount time
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
+ if ((mask & MAY_EXEC) && !execute_ok(inode))
+ return -EACCES;
+ else
+ return 0;
+ } else /* file mode might have been restricted at mount time
on the client (above and beyond ACL on servers) for
servers which do not support setting and viewing mode bits,
so allowing client to check permissions is useful */
@@ -765,6 +768,7 @@ const struct file_operations cifs_dir_ops = {
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
.unlocked_ioctl = cifs_ioctl,
+ .llseek = generic_file_llseek,
};
static void
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index c5916228243..75b1fa90b2c 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -146,6 +146,9 @@ int coda_permission(struct inode *inode, int mask)
if (!mask)
return 0;
+ if ((mask & MAY_EXEC) && !execute_ok(inode))
+ return -EACCES;
+
lock_kernel();
if (coda_cache_check(inode, mask))
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index c51365422aa..773f2ce9aa0 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -43,7 +43,7 @@ const struct file_operations coda_ioctl_operations = {
/* the coda pioctl inode ops */
static int coda_ioctl_permission(struct inode *inode, int mask)
{
- return 0;
+ return (mask & MAY_EXEC) ? -EACCES : 0;
}
static int coda_pioctl(struct inode * inode, struct file * filp,
diff --git a/fs/compat.c b/fs/compat.c
index 5f9ec449c79..cb36245f9fe 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -869,7 +869,7 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
buf.dirent = dirent;
error = vfs_readdir(file, compat_fillonedir, &buf);
- if (error >= 0)
+ if (buf.result)
error = buf.result;
fput(file);
@@ -956,9 +956,8 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
buf.error = 0;
error = vfs_readdir(file, compat_filldir, &buf);
- if (error < 0)
- goto out_putf;
- error = buf.error;
+ if (error >= 0)
+ error = buf.error;
lastdirent = buf.previous;
if (lastdirent) {
if (put_user(file->f_pos, &lastdirent->d_off))
@@ -966,8 +965,6 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
else
error = count - buf.count;
}
-
-out_putf:
fput(file);
out:
return error;
@@ -1047,19 +1044,16 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
buf.error = 0;
error = vfs_readdir(file, compat_filldir64, &buf);
- if (error < 0)
- goto out_putf;
- error = buf.error;
+ if (error >= 0)
+ error = buf.error;
lastdirent = buf.previous;
if (lastdirent) {
typeof(lastdirent->d_off) d_off = file->f_pos;
- error = -EFAULT;
if (__put_user_unaligned(d_off, &lastdirent->d_off))
- goto out_putf;
- error = count - buf.count;
+ error = -EFAULT;
+ else
+ error = count - buf.count;
}
-
-out_putf:
fput(file);
out:
return error;
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
index bf74973b049..932a92b3148 100644
--- a/fs/configfs/symlink.c
+++ b/fs/configfs/symlink.c
@@ -108,18 +108,18 @@ out:
}
-static int get_target(const char *symname, struct nameidata *nd,
+static int get_target(const char *symname, struct path *path,
struct config_item **target)
{
int ret;
- ret = path_lookup(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, nd);
+ ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
if (!ret) {
- if (nd->path.dentry->d_sb == configfs_sb) {
- *target = configfs_get_config_item(nd->path.dentry);
+ if (path->dentry->d_sb == configfs_sb) {
+ *target = configfs_get_config_item(path->dentry);
if (!*target) {
ret = -ENOENT;
- path_put(&nd->path);
+ path_put(path);
}
} else
ret = -EPERM;
@@ -132,7 +132,7 @@ static int get_target(const char *symname, struct nameidata *nd,
int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
int ret;
- struct nameidata nd;
+ struct path path;
struct configfs_dirent *sd;
struct config_item *parent_item;
struct config_item *target_item;
@@ -159,7 +159,7 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna
!type->ct_item_ops->allow_link)
goto out_put;
- ret = get_target(symname, &nd, &target_item);
+ ret = get_target(symname, &path, &target_item);
if (ret)
goto out_put;
@@ -174,7 +174,7 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna
}
config_item_put(target_item);
- path_put(&nd.path);
+ path_put(&path);
out_put:
config_item_put(parent_item);
diff --git a/fs/dcache.c b/fs/dcache.c
index e7a1a99b746..a1d86c7f3e6 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -69,6 +69,7 @@ struct dentry_stat_t dentry_stat = {
static void __d_free(struct dentry *dentry)
{
+ WARN_ON(!list_empty(&dentry->d_alias));
if (dname_external(dentry))
kfree(dentry->d_name.name);
kmem_cache_free(dentry_cache, dentry);
@@ -174,9 +175,12 @@ static struct dentry *d_kill(struct dentry *dentry)
dentry_stat.nr_dentry--; /* For d_free, below */
/*drops the locks, at that point nobody can reach this dentry */
dentry_iput(dentry);
- parent = dentry->d_parent;
+ if (IS_ROOT(dentry))
+ parent = NULL;
+ else
+ parent = dentry->d_parent;
d_free(dentry);
- return dentry == parent ? NULL : parent;
+ return parent;
}
/*
@@ -666,11 +670,12 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
BUG();
}
- parent = dentry->d_parent;
- if (parent == dentry)
+ if (IS_ROOT(dentry))
parent = NULL;
- else
+ else {
+ parent = dentry->d_parent;
atomic_dec(&parent->d_count);
+ }
list_del(&dentry->d_u.d_child);
detached++;
@@ -977,6 +982,15 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
return d_alloc(parent, &q);
}
+/* the caller must hold dcache_lock */
+static void __d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+ if (inode)
+ list_add(&dentry->d_alias, &inode->i_dentry);
+ dentry->d_inode = inode;
+ fsnotify_d_instantiate(dentry, inode);
+}
+
/**
* d_instantiate - fill in inode information for a dentry
* @entry: dentry to complete
@@ -996,10 +1010,7 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
{
BUG_ON(!list_empty(&entry->d_alias));
spin_lock(&dcache_lock);
- if (inode)
- list_add(&entry->d_alias, &inode->i_dentry);
- entry->d_inode = inode;
- fsnotify_d_instantiate(entry, inode);
+ __d_instantiate(entry, inode);
spin_unlock(&dcache_lock);
security_d_instantiate(entry, inode);
}
@@ -1029,7 +1040,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
unsigned int hash = entry->d_name.hash;
if (!inode) {
- entry->d_inode = NULL;
+ __d_instantiate(entry, NULL);
return NULL;
}
@@ -1048,9 +1059,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
return alias;
}
- list_add(&entry->d_alias, &inode->i_dentry);
- entry->d_inode = inode;
- fsnotify_d_instantiate(entry, inode);
+ __d_instantiate(entry, inode);
return NULL;
}
@@ -1111,69 +1120,71 @@ static inline struct hlist_head *d_hash(struct dentry *parent,
}
/**
- * d_alloc_anon - allocate an anonymous dentry
+ * d_obtain_alias - find or allocate a dentry for a given inode
* @inode: inode to allocate the dentry for
*
- * This is similar to d_alloc_root. It is used by filesystems when
- * creating a dentry for a given inode, often in the process of
- * mapping a filehandle to a dentry. The returned dentry may be
- * anonymous, or may have a full name (if the inode was already
- * in the cache). The file system may need to make further
- * efforts to connect this dentry into the dcache properly.
+ * Obtain a dentry for an inode resulting from NFS filehandle conversion or
+ * similar open by handle operations. The returned dentry may be anonymous,
+ * or may have a full name (if the inode was already in the cache).
*
- * When called on a directory inode, we must ensure that
- * the inode only ever has one dentry. If a dentry is
- * found, that is returned instead of allocating a new one.
+ * When called on a directory inode, we must ensure that the inode only ever
+ * has one dentry. If a dentry is found, that is returned instead of
+ * allocating a new one.
*
* On successful return, the reference to the inode has been transferred
- * to the dentry. If %NULL is returned (indicating kmalloc failure),
- * the reference on the inode has not been released.
+ * to the dentry. In case of an error the reference on the inode is released.
+ * To make it easier to use in export operations a %NULL or IS_ERR inode may
+ * be passed in and will be the error will be propagate to the return value,
+ * with a %NULL @inode replaced by ERR_PTR(-ESTALE).
*/
-
-struct dentry * d_alloc_anon(struct inode *inode)
+struct dentry *d_obtain_alias(struct inode *inode)