mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (46 commits) [PATCH] fs: add a sanity check in d_free [PATCH] i_version: remount support [patch] vfs: make security_inode_setattr() calling consistent [patch 1/3] FS_MBCACHE: don't needlessly make it built-in [PATCH] move executable checking into ->permission() [PATCH] fs/dcache.c: update comment of d_validate() [RFC PATCH] touch_mnt_namespace when the mount flags change [PATCH] reiserfs: add missing llseek method [PATCH] fix ->llseek for more directories [PATCH vfs-2.6 6/6] vfs: add LOOKUP_RENAME_TARGET intent [PATCH vfs-2.6 5/6] vfs: remove LOOKUP_PARENT from non LOOKUP_PARENT lookup [PATCH vfs-2.6 4/6] vfs: remove unnecessary fsnotify_d_instantiate() [PATCH vfs-2.6 3/6] vfs: add __d_instantiate() helper [PATCH vfs-2.6 2/6] vfs: add d_ancestor() [PATCH vfs-2.6 1/6] vfs: replace parent == dentry->d_parent by IS_ROOT() [PATCH] get rid of on-stack dentry in udf [PATCH 2/2] anondev: switch to IDA [PATCH 1/2] anondev: init IDR statically [JFFS2] Use d_splice_alias() not d_add() in jffs2_lookup() [PATCH] Optimise NFS readdir hack slightly. ...
This commit is contained in:
commit
5ed487bc2c
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -312,19 +312,6 @@ static inline int check_space(struct dm_table *t)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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 = {
|
||||
|
10
fs/attr.c
10
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))
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
22
fs/compat.c
22
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;
|
||||
|
@ -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);
|
||||
|
188
fs/dcache.c
188
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)
|
||||
{
|
||||
static const struct qstr anonstring = { .name = "" };
|
||||
struct dentry *tmp;
|
||||
struct dentry *res;
|
||||
|
||||
if ((res = d_find_alias(inode))) {
|
||||
iput(inode);
|
||||
return res;
|
||||
}
|
||||
if (!inode)
|
||||
return ERR_PTR(-ESTALE);
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
res = d_find_alias(inode);
|
||||
if (res)
|
||||
goto out_iput;
|
||||
|
||||
tmp = d_alloc(NULL, &anonstring);
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
|
||||
if (!tmp) {
|
||||
res = ERR_PTR(-ENOMEM);
|
||||
goto out_iput;
|
||||
}
|
||||
tmp->d_parent = tmp; /* make sure dput doesn't croak */
|
||||
|
||||
|
||||
spin_lock(&dcache_lock);
|
||||
res = __d_find_alias(inode, 0);
|
||||
if (!res) {
|
||||
/* attach a disconnected dentry */
|
||||
res = tmp;
|
||||
tmp = NULL;
|
||||
spin_lock(&res->d_lock);
|
||||
res->d_sb = inode->i_sb;
|
||||
res->d_parent = res;
|
||||
res->d_inode = inode;
|
||||
res->d_flags |= DCACHE_DISCONNECTED;
|
||||
res->d_flags &= ~DCACHE_UNHASHED;
|
||||
list_add(&res->d_alias, &inode->i_dentry);
|
||||
hlist_add_head(&res->d_hash, &inode->i_sb->s_anon);
|
||||
spin_unlock(&res->d_lock);
|
||||
|
||||
inode = NULL; /* don't drop reference */
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
|
||||
if (inode)
|
||||
iput(inode);
|
||||
if (tmp)
|
||||
if (res) {
|
||||
spin_unlock(&dcache_lock);
|
||||
dput(tmp);
|
||||
goto out_iput;
|
||||
}
|
||||
|
||||
/* attach a disconnected dentry */
|
||||
spin_lock(&tmp->d_lock);
|
||||
tmp->d_sb = inode->i_sb;
|
||||
tmp->d_inode = inode;
|
||||
tmp->d_flags |= DCACHE_DISCONNECTED;
|
||||
tmp->d_flags &= ~DCACHE_UNHASHED;
|
||||
list_add(&tmp->d_alias, &inode->i_dentry);
|
||||
hlist_add_head(&tmp->d_hash, &inode->i_sb->s_anon);
|
||||
spin_unlock(&tmp->d_lock);
|
||||
|
||||
spin_unlock(&dcache_lock);
|
||||
return tmp;
|
||||
|
||||
out_iput:
|
||||
iput(inode);
|
||||
return res;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(d_obtain_alias);
|
||||
|
||||
/**
|
||||
* d_splice_alias - splice a disconnected dentry into the tree if one exists
|
||||
@ -1200,17 +1211,14 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
|
||||
new = __d_find_alias(inode, 1);
|
||||
if (new) {
|
||||
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
|
||||
fsnotify_d_instantiate(new, inode);
|
||||
spin_unlock(&dcache_lock);
|
||||
security_d_instantiate(new, inode);
|
||||
d_rehash(dentry);
|
||||
d_move(new, dentry);
|
||||
iput(inode);
|
||||
} else {
|
||||
/* d_instantiate takes dcache_lock, so we do it by hand */
|
||||
list_add(&dentry->d_alias, &inode->i_dentry);
|
||||
dentry->d_inode = inode;
|
||||
fsnotify_d_instantiate(dentry, inode);
|
||||
/* already taking dcache_lock, so d_add() by hand */
|
||||
__d_instantiate(dentry, inode);
|
||||
spin_unlock(&dcache_lock);
|
||||
security_d_instantiate(dentry, inode);
|
||||
d_rehash(dentry);
|
||||
@ -1293,8 +1301,7 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
|
||||
* d_instantiate() by hand because it takes dcache_lock which
|
||||
* we already hold.
|
||||
*/
|
||||
list_add(&found->d_alias, &inode->i_dentry);
|
||||
found->d_inode = inode;
|
||||
__d_instantiate(found, inode);
|
||||
spin_unlock(&dcache_lock);
|
||||
security_d_instantiate(found, inode);
|
||||
return found;
|
||||
@ -1456,8 +1463,6 @@ out:
|
||||
* d_validate - verify dentry provided from insecure source
|
||||
* @dentry: The dentry alleged to be valid child of @dparent
|
||||
* @dparent: The parent dentry (known to be valid)
|
||||
* @hash: Hash of the dentry
|
||||
* @len: Length of the name
|
||||
*
|
||||
* An insecure source has sent us a dentry, here we verify it and dget() it.
|
||||
* This is used by ncpfs in its readdir implementation.
|
||||
@ -1714,18 +1719,23 @@ void d_move(struct dentry * dentry, struct dentry * target)
|
||||
spin_unlock(&dcache_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper that returns 1 if p1 is a parent of p2, else 0
|
||||
/**
|
||||
* d_ancestor - search for an ancestor
|
||||
* @p1: ancestor dentry
|
||||
* @p2: child dentry
|
||||
*
|
||||
* Returns the ancestor dentry of p2 which is a child of p1, if p1 is
|
||||
* an ancestor of p2, else NULL.
|
||||
*/
|
||||
static int d_isparent(struct dentry *p1, struct dentry *p2)
|
||||
struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2)
|
||||
{
|
||||
struct dentry *p;
|
||||
|
||||
for (p = p2; p->d_parent != p; p = p->d_parent) {
|
||||
for (p = p2; !IS_ROOT(p); p = p->d_parent) {
|
||||
if (p->d_parent == p1)
|
||||
return 1;
|
||||
return p;
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1749,7 +1759,7 @@ static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias)
|
||||
|
||||
/* Check for loops */
|
||||
ret = ERR_PTR(-ELOOP);
|
||||
if (d_isparent(alias, dentry))
|
||||
if (d_ancestor(alias, dentry))
|
||||
goto out_err;
|
||||
|
||||
/* See lock_rename() */
|
||||
@ -1822,7 +1832,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
|
||||
|
||||
if (!inode) {
|
||||
actual = dentry;
|
||||
dentry->d_inode = NULL;
|
||||
__d_instantiate(dentry, NULL);
|
||||
goto found_lock;
|
||||
}
|
||||
|
||||
@ -2149,32 +2159,27 @@ out:
|
||||
* Caller must ensure that "new_dentry" is pinned before calling is_subdir()
|
||||
*/
|
||||
|
||||
int is_subdir(struct dentry * new_dentry, struct dentry * old_dentry)
|
||||
int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
|
||||
{
|
||||
int result;
|
||||
struct dentry * saved = new_dentry;
|
||||
unsigned long seq;
|
||||
|
||||
/* need rcu_readlock to protect against the d_parent trashing due to
|
||||
* d_move
|
||||
/* FIXME: This is old behavior, needed? Please check callers. */
|
||||
if (new_dentry == old_dentry)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Need rcu_readlock to protect against the d_parent trashing
|
||||
* due to d_move
|
||||
*/
|
||||
rcu_read_lock();
|
||||
do {
|
||||
do {
|
||||
/* for restarting inner loop in case of seq retry */
|
||||
new_dentry = saved;
|
||||
result = 0;
|
||||
seq = read_seqbegin(&rename_lock);
|
||||
for (;;) {
|
||||
if (new_dentry != old_dentry) {
|
||||
struct dentry * parent = new_dentry->d_parent;
|
||||
if (parent == new_dentry)
|
||||
break;
|
||||
new_dentry = parent;
|
||||
continue;
|
||||
}
|
||||
if (d_ancestor(old_dentry, new_dentry))
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
result = 0;
|
||||
} while (read_seqretry(&rename_lock, seq));
|
||||
rcu_read_unlock();
|
||||
|
||||
@ -2344,7 +2349,6 @@ void __init vfs_caches_init(unsigned long mempages)
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(d_alloc);
|
||||
EXPORT_SYMBOL(d_alloc_anon);
|
||||
EXPORT_SYMBOL(d_alloc_root);
|
||||
EXPORT_SYMBOL(d_delete);
|
||||
EXPORT_SYMBOL(d_find_alias);
|
||||
|
10
fs/dquot.c
10
fs/dquot.c
@ -1805,19 +1805,19 @@ int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
|
||||
}
|
||||
|
||||
/* Actual function called from quotactl() */
|
||||
int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path,
|
||||
int vfs_quota_on(struct super_block *sb, int type, int format_id, char *name,
|
||||
int remount)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
if (remount)
|
||||
return vfs_quota_on_remount(sb, type);
|
||||
|
||||
error = path_lookup(path, LOOKUP_FOLLOW, &nd);
|
||||
error = kern_path(name, LOOKUP_FOLLOW, &path);
|
||||
if (!error) {
|
||||
error = vfs_quota_on_path(sb, type, format_id, &nd.path);
|
||||
path_put(&nd.path);
|
||||
error = vfs_quota_on_path(sb, type, format_id, &path);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -471,31 +471,26 @@ out:
|
||||
*/
|
||||
static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
|
||||
{
|
||||
struct path path;
|
||||
int rc;
|
||||
struct nameidata nd;
|
||||
struct dentry *lower_root;
|
||||
struct vfsmount *lower_mnt;
|
||||
|
||||
memset(&nd, 0, sizeof(struct nameidata));
|
||||
rc = path_lookup(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
|
||||
rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
|
||||
if (rc) {
|
||||
ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n");
|
||||
goto out;
|
||||
}
|
||||
lower_root = nd.path.dentry;
|
||||
lower_mnt = nd.path.mnt;
|
||||
ecryptfs_set_superblock_lower(sb, lower_root->d_sb);
|
||||
sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
|
||||
sb->s_blocksize = lower_root->d_sb->s_blocksize;
|
||||
ecryptfs_set_dentry_lower(sb->s_root, lower_root);
|
||||
ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt);
|
||||
rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0);
|
||||
ecryptfs_set_superblock_lower(sb, path.dentry->d_sb);
|
||||
sb->s_maxbytes = path.dentry->d_sb->s_maxbytes;
|
||||
sb->s_blocksize = path.dentry->d_sb->s_blocksize;
|
||||
ecryptfs_set_dentry_lower(sb->s_root, path.dentry);
|
||||
ecryptfs_set_dentry_lower_mnt(sb->s_root, path.mnt);
|
||||
rc = ecryptfs_interpose(path.dentry, sb->s_root, sb, 0);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
rc = 0;
|
||||
goto out;
|
||||
out_free:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
@ -112,35 +112,14 @@ struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
|
||||
|
||||
struct dentry *efs_get_parent(struct dentry *child)
|
||||
{
|
||||
struct dentry *parent;
|
||||
struct inode *inode;
|
||||
struct dentry *parent = ERR_PTR(-ENOENT);
|
||||
efs_ino_t ino;
|
||||
long error;
|
||||
|
||||
lock_kernel();
|
||||
|
||||
error = -ENOENT;
|
||||
ino = efs_find_entry(child->d_inode, "..", 2);
|
||||
if (!ino)
|
||||
goto fail;
|
||||
|
||||
inode = efs_iget(child->d_inode->i_sb, ino);
|
||||
if (IS_ERR(inode)) {
|
||||
error = PTR_ERR(inode);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
error = -ENOMEM;
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent)
|
||||
goto fail_iput;
|
||||
|
||||
if (ino)
|
||||
parent = d_obtain_alias(efs_iget(child->d_inode->i_sb, ino));
|
||||
unlock_kernel();
|
||||
|
||||
return parent;
|
||||
|
||||
fail_iput:
|
||||
iput(inode);
|
||||
fail:
|
||||
unlock_kernel();
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
@ -94,9 +94,8 @@ find_disconnected_root(struct dentry *dentry)
|
||||
* It may already be, as the flag isn't always updated when connection happens.
|
||||
*/
|
||||
static int
|
||||
reconnect_path(struct vfsmount *mnt, struct dentry *target_dir)
|
||||
reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
|
||||
{
|
||||
char nbuf[NAME_MAX+1];
|
||||
int noprogress = 0;
|
||||
int err = -ESTALE;
|
||||
|
||||
@ -281,13 +280,14 @@ static int get_name(struct vfsmount *mnt, struct dentry *dentry,
|
||||
int old_seq = buffer.sequence;
|
||||
|
||||
error = vfs_readdir(file, filldir_one, &buffer);
|
||||
if (buffer.found) {
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (error < 0)
|
||||
break;
|
||||
|
||||
error = 0;
|
||||
if (buffer.found)
|
||||
break;
|
||||
error = -ENOENT;
|
||||
if (old_seq == buffer.sequence)
|
||||
break;
|
||||
@ -360,14 +360,13 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
|
||||
{
|
||||
const struct export_operations *nop = mnt->mnt_sb->s_export_op;
|
||||
struct dentry *result, *alias;
|
||||
char nbuf[NAME_MAX+1];
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Try to get any dentry for the given file handle from the filesystem.
|
||||
*/
|
||||
result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
|
||||
if (!result)
|
||||
result = ERR_PTR(-ESTALE);
|
||||
if (IS_ERR(result))
|
||||
return result;
|
||||
|
||||
@ -381,7 +380,7 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
|
||||
* filesystem root.
|
||||
*/
|
||||
if (result->d_flags & DCACHE_DISCONNECTED) {
|
||||
err = reconnect_path(mnt, result);
|
||||
err = reconnect_path(mnt, result, nbuf);
|
||||
if (err)
|
||||
goto err_result;
|
||||
}
|
||||
@ -397,7 +396,6 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
|
||||
* It's not a directory. Life is a little more complicated.
|
||||
*/
|
||||
struct dentry *target_dir, *nresult;
|
||||
char nbuf[NAME_MAX+1];
|
||||
|
||||
/*
|
||||
* See if either the dentry we just got from the filesystem
|
||||
@ -422,8 +420,6 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
|
||||
|
||||
target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
|
||||
fh_len, fileid_type);
|
||||
if (!target_dir)
|
||||
goto err_result;
|
||||
err = PTR_ERR(target_dir);
|
||||
if (IS_ERR(target_dir))
|
||||
goto err_result;
|
||||
@ -433,7 +429,7 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
|
||||
* connected to the filesystem root. The VFS really doesn't
|
||||
* like disconnected directories..
|
||||
*/
|
||||
err = reconnect_path(mnt, target_dir);
|
||||
err = reconnect_path(mnt, target_dir, nbuf);
|
||||
if (err) {
|
||||
dput(target_dir);
|
||||
goto err_result;
|
||||
|
@ -354,11 +354,11 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
|
||||
* (as a parameter - res_dir). Page is returned mapped and unlocked.
|
||||
* Entry is guaranteed to be valid.
|
||||
*/
|
||||
struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
|
||||
struct dentry *dentry, struct page ** res_page)
|
||||
struct ext2_dir_entry_2 *ext2_find_entry (struct inode * dir,
|
||||
struct qstr *child, struct page ** res_page)
|
||||
{
|
||||
const char *name = dentry->d_name.name;
|
||||
int namelen = dentry->d_name.len;
|
||||
const char *name = child->name;
|
||||
int namelen = child->len;
|
||||
unsigned reclen = EXT2_DIR_REC_LEN(namelen);
|
||||
unsigned long start, n;
|
||||
unsigned long npages = dir_pages(dir);
|
||||
@ -431,13 +431,13 @@ struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
|
||||
return de;
|
||||
}
|
||||
|
||||
ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry)
|
||||
ino_t ext2_inode_by_name(struct inode *dir, struct qstr *child)
|
||||
{
|
||||
ino_t res = 0;
|
||||
struct ext2_dir_entry_2 * de;
|
||||
struct ext2_dir_entry_2 *de;
|
||||
struct page *page;
|
||||
|
||||
de = ext2_find_entry (dir, dentry, &page);
|
||||
de = ext2_find_entry (dir, child, &page);
|
||||
if (de) {
|
||||
res = le32_to_cpu(de->inode);
|
||||
ext2_put_page(page);
|
||||
|
@ -105,9 +105,9 @@ extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_wind
|
||||
|
||||
/* dir.c */
|
||||
extern int ext2_add_link (struct dentry *, struct inode *);
|
||||
extern ino_t ext2_inode_by_name(struct inode *, struct dentry *);
|
||||
extern ino_t ext2_inode_by_name(struct inode *, struct qstr *);
|
||||
extern int ext2_make_empty(struct inode *, struct inode *);
|
||||
extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct dentry *, struct page **);
|
||||
extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct qstr *, struct page **);
|
||||
extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
|
||||
extern int ext2_empty_dir (struct inode *);
|
||||
extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
|
||||
|
@ -60,7 +60,7 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
|
||||
if (dentry->d_name.len > EXT2_NAME_LEN)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
|
||||
ino = ext2_inode_by_name(dir, dentry);
|
||||
ino = ext2_inode_by_name(dir, &dentry->d_name);
|
||||
inode = NULL;
|
||||
if (ino) {
|
||||
inode = ext2_iget(dir->i_sb, ino);
|
||||
@ -72,27 +72,11 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
|
||||
|
||||
struct dentry *ext2_get_parent(struct dentry *child)
|
||||
{
|
||||
unsigned long ino;
|
||||
struct dentry *parent;
|
||||
struct inode *inode;
|
||||
struct dentry dotdot;
|
||||
|
||||
dotdot.d_name.name = "..";
|
||||
dotdot.d_name.len = 2;
|
||||
|
||||
ino = ext2_inode_by_name(child->d_inode, &dotdot);
|
||||
struct qstr dotdot = {.name = "..", .len = 2};
|
||||
unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot);
|
||||
if (!ino)
|
||||
return ERR_PTR(-ENOENT);
|
||||
inode = ext2_iget(child->d_inode->i_sb, ino);
|
||||
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent) {
|
||||
iput(inode);
|
||||
parent = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return parent;
|
||||
return d_obtain_alias(ext2_iget(child->d_inode->i_sb, ino));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -257,7 +241,7 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry)
|
||||
struct page * page;
|
||||
int err = -ENOENT;
|
||||
|
||||
de = ext2_find_entry (dir, dentry, &page);
|
||||
de = ext2_find_entry (dir, &dentry->d_name, &page);
|
||||
if (!de)
|
||||
goto out;
|
||||
|
||||
@ -299,7 +283,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
|
||||
struct ext2_dir_entry_2 * old_de;
|
||||
int err = -ENOENT;
|
||||
|
||||
old_de = ext2_find_entry (old_dir, old_dentry, &old_page);
|
||||
old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page);
|
||||
if (!old_de)
|
||||
goto out;
|
||||
|
||||
@ -319,7 +303,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
|
||||
goto out_dir;
|
||||
|
||||
err = -ENOENT;
|
||||
new_de = ext2_find_entry (new_dir, new_dentry, &new_page);
|
||||
new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page);
|
||||
if (!new_de)
|
||||
goto out_dir;
|
||||
inode_inc_link_count(old_inode);
|
||||
|
@ -159,7 +159,7 @@ static void dx_set_count (struct dx_entry *entries, unsigned value);
|
||||
static void dx_set_limit (struct dx_entry *entries, unsigned value);
|
||||
static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
|
||||
static unsigned dx_node_limit (struct inode *dir);
|
||||
static struct dx_frame *dx_probe(struct dentry *dentry,
|
||||
static struct dx_frame *dx_probe(struct qstr *entry,
|
||||
struct inode *dir,
|
||||
struct dx_hash_info *hinfo,
|
||||
struct dx_frame *frame,
|
||||
@ -176,8 +176,9 @@ static int ext3_htree_next_block(struct inode *dir, __u32 hash,
|
||||
struct dx_frame *frame,
|
||||
struct dx_frame *frames,
|
||||
__u32 *start_hash);
|
||||
static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
|
||||
struct ext3_dir_entry_2 **res_dir, int *err);
|
||||
static struct buffer_head * ext3_dx_find_entry(struct inode *dir,
|
||||
struct qstr *entry, struct ext3_dir_entry_2 **res_dir,
|
||||
int *err);
|
||||
static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
|
||||
struct inode *inode);
|
||||
|
||||
@ -342,7 +343,7 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
|
||||
* back to userspace.
|
||||
*/
|
||||
static struct dx_frame *
|
||||
dx_probe(struct dentry *dentry, struct inode *dir,
|
||||
dx_probe(struct qstr *entry, struct inode *dir,
|
||||
struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
|
||||
{
|
||||
unsigned count, indirect;
|
||||
@ -353,8 +354,6 @@ dx_probe(struct dentry *dentry, struct inode *dir,
|
||||
u32 hash;
|
||||
|
||||
frame->bh = NULL;
|
||||
if (dentry)
|
||||
dir = dentry->d_parent->d_inode;
|
||||
if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
|
||||
goto fail;
|
||||
root = (struct dx_root *) bh->b_data;
|
||||
@ -370,8 +369,8 @@ dx_probe(struct dentry *dentry, struct inode *dir,
|
||||
}
|
||||
hinfo->hash_version = root->info.hash_version;
|
||||
hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed;
|
||||
if (dentry)
|
||||
ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
|
||||
if (entry)
|
||||
ext3fs_dirhash(entry->name, entry->len, hinfo);
|
||||
hash = hinfo->hash;
|
||||
|
||||
if (root->info.unused_flags & 1) {
|
||||
@ -803,15 +802,15 @@ static inline int ext3_match (int len, const char * const name,
|
||||
*/
|
||||
static inline int search_dirblock(struct buffer_head * bh,
|
||||
struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
struct qstr *child,
|
||||
unsigned long offset,
|
||||
struct ext3_dir_entry_2 ** res_dir)
|
||||
{
|
||||
struct ext3_dir_entry_2 * de;
|
||||
char * dlimit;
|
||||
int de_len;
|
||||
const char *name = dentry->d_name.name;
|
||||
int namelen = dentry->d_name.len;
|
||||
const char *name = child->name;
|
||||
int namelen = child->len;
|
||||
|
||||
de = (struct ext3_dir_entry_2 *) bh->b_data;
|
||||
dlimit = bh->b_data + dir->i_sb->s_blocksize;
|
||||
@ -850,8 +849,9 @@ static inline int search_dirblock(struct buffer_head * bh,
|
||||
* The returned buffer_head has ->b_count elevated. The caller is expected
|
||||
* to brelse() it when appropriate.
|
||||
*/
|
||||
static struct buffer_head * ext3_find_entry (struct dentry *dentry,
|
||||
struct ext3_dir_entry_2 ** res_dir)
|
||||
static struct buffer_head *ext3_find_entry(struct inode *dir,
|
||||
struct qstr *entry,
|
||||
struct ext3_dir_entry_2 **res_dir)
|
||||
{
|
||||
struct super_block * sb;
|
||||
struct buffer_head * bh_use[NAMEI_RA_SIZE];
|
||||
@ -863,16 +863,15 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
|
||||
buffer */
|
||||
int num = 0;
|
||||
int nblocks, i, err;
|
||||
struct inode *dir = dentry->d_parent->d_inode;
|
||||
int namelen;
|
||||
|
||||
*res_dir = NULL;
|
||||
sb = dir->i_sb;
|
||||
namelen = dentry->d_name.len;
|
||||
namelen = entry->len;
|
||||
if (namelen > EXT3_NAME_LEN)
|
||||
return NULL;
|
||||
if (is_dx(dir)) {
|
||||
bh = ext3_dx_find_entry(dentry, res_dir, &err);
|
||||
bh = ext3_dx_find_entry(dir, entry, res_dir, &err);
|
||||
/*
|
||||
* On success, or if the error was file not found,
|
||||
* return. Otherwise, fall back to doing a search the
|
||||
@ -923,7 +922,7 @@ restart:
|
||||
brelse(bh);
|
||||
goto next;
|
||||
}
|
||||
i = search_dirblock(bh, dir, dentry,
|
||||
i = search_dirblock(bh, dir, entry,
|
||||
block << EXT3_BLOCK_SIZE_BITS(sb), res_dir);
|
||||
if (i == 1) {
|
||||
EXT3_I(dir)->i_dir_start_lookup = block;
|
||||
@ -957,8 +956,9 @@ cleanup_and_exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
|
||||
struct ext3_dir_entry_2 **res_dir, int *err)
|
||||
static struct buffer_head * ext3_dx_find_entry(struct inode *dir,
|
||||
struct qstr *entry, struct ext3_dir_entry_2 **res_dir,
|
||||
int *err)
|
||||
{
|
||||
struct super_block * sb;
|
||||
struct dx_hash_info hinfo;
|
||||
@ -968,14 +968,13 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
|
||||
struct buffer_head *bh;
|
||||
unsigned long block;
|
||||
int retval;
|
||||
int namelen = dentry->d_name.len;
|
||||
const u8 *name = dentry->d_name.name;
|
||||
struct inode *dir = dentry->d_parent->d_inode;
|
||||
int namelen = entry->len;
|
||||
const u8 *name = entry->name;
|
||||
|
||||
sb = dir->i_sb;
|
||||
/* NFS may look up ".." - look at dx_root directory block */
|
||||
if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
|
||||
if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err)))
|
||||
if (namelen > 2 || name[0] != '.'|| (namelen == 2 && name[1] != '.')) {
|
||||
if (!(frame = dx_probe(entry, dir, &hinfo, frames, err)))
|
||||
return NULL;
|
||||
} else {
|
||||
frame = frames;
|
||||
@ -1036,7 +1035,7 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
|
||||
if (dentry->d_name.len > EXT3_NAME_LEN)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
|
||||
bh = ext3_find_entry(dentry, &de);
|
||||
bh = ext3_find_entry(dir, &dentry->d_name, &de);
|
||||
inode = NULL;
|
||||
if (bh) {
|
||||
unsigned long ino = le32_to_cpu(de->inode);
|
||||
@ -1057,18 +1056,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
|
||||
struct dentry *ext3_get_parent(struct dentry *child)
|
||||
{
|
||||
unsigned long ino;
|
||||
struct dentry *parent;
|
||||
struct inode *inode;
|
||||
struct dentry dotdot;
|
||||
struct qstr dotdot = {.name = "..", .len = 2};
|
||||
struct ext3_dir_entry_2 * de;
|
||||
struct buffer_head *bh;
|
||||
|
||||
dotdot.d_name.name = "..";
|
||||
dotdot.d_name.len = 2;
|
||||
dotdot.d_parent = child; /* confusing, isn't it! */
|
||||
|
||||
bh = ext3_find_entry(&dotdot, &de);
|
||||
inode = NULL;
|
||||
bh = ext3_find_entry(child->d_inode, &dotdot, &de);
|
||||
if (!bh)
|
||||
return ERR_PTR(-ENOENT);
|
||||
ino = le32_to_cpu(de->inode);
|
||||
@ -1080,16 +1072,7 @@ struct dentry *ext3_get_parent(struct dentry *child)
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
inode = ext3_iget(child->d_inode->i_sb, ino);
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent) {
|
||||
iput(inode);
|
||||
parent = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return parent;
|
||||
return d_obtain_alias(ext3_iget(child->d_inode->i_sb, ino));
|
||||
}
|
||||
|
||||
#define S_SHIFT 12
|
||||
@ -1503,7 +1486,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
|
||||
struct ext3_dir_entry_2 *de;
|
||||
int err;
|
||||
|
||||
frame = dx_probe(dentry, NULL, &hinfo, frames, &err);
|
||||
frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err);
|
||||
if (!frame)
|
||||
return err;
|
||||
entries = frame->entries;
|
||||
@ -2056,7 +2039,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
|
||||
return PTR_ERR(handle);
|
||||
|
||||
retval = -ENOENT;
|
||||
bh = ext3_find_entry (dentry, &de);
|
||||
bh = ext3_find_entry(dir, &dentry->d_name, &de);
|
||||
if (!bh)
|
||||
goto end_rmdir;
|
||||
|
||||
@ -2118,7 +2101,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
|
||||
handle->h_sync = 1;
|
||||
|
||||
retval = -ENOENT;
|
||||
bh = ext3_find_entry (dentry, &de);
|
||||
bh = ext3_find_entry(dir, &dentry->d_name, &de);
|
||||
if (!bh)
|
||||
goto end_unlink;
|
||||
|
||||
@ -2276,7 +2259,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
|
||||
if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
|
||||
handle->h_sync = 1;
|
||||
|
||||
old_bh = ext3_find_entry (old_dentry, &old_de);
|
||||
old_bh = ext3_find_entry(old_dir, &old_dentry->d_name, &old_de);
|
||||
/*
|
||||
* Check for inode number is _not_ due to possible IO errors.
|
||||
* We might rmdir the source, keep it as pwd of some process
|
||||
@ -2289,7 +2272,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
|
||||
goto end_rename;
|
||||
|
||||
new_inode = new_dentry->d_inode;
|
||||
new_bh = ext3_find_entry (new_dentry, &new_de);
|
||||
new_bh = ext3_find_entry(new_dir, &new_dentry->d_name, &new_de);
|
||||
if (new_bh) {
|
||||
if (!new_inode) {
|
||||
brelse (new_bh);
|
||||
@ -2355,7 +2338,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
|
||||
struct buffer_head *old_bh2;
|
||||
struct ext3_dir_entry_2 *old_de2;
|
||||
|
||||
old_bh2 = ext3_find_entry(old_dentry, &old_de2);
|
||||
old_bh2 = ext3_find_entry(old_dir, &old_dentry->d_name,
|
||||
&old_de2);
|
||||
if (old_bh2) {
|
||||
retval = ext3_delete_entry(handle, old_dir,
|
||||
old_de2, old_bh2);
|
||||
|
@ -2794,30 +2794,30 @@ static int ext3_quota_on_mount(struct super_block *sb, int type)
|
||||
* Standard function to be called on quota_on
|
||||
*/
|
||||
static int ext3_quota_on(struct super_block *sb, int type, int format_id,
|
||||
char *path, int remount)
|
||||
char *name, int remount)
|
||||
{
|
||||
int err;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
|
||||
if (!test_opt(sb, QUOTA))
|
||||
return -EINVAL;
|
||||
/* When remounting, no checks are needed and in fact, path is NULL */
|
||||
/* When remounting, no checks are needed and in fact, name is NULL */
|
||||
if (remount)
|
||||
return vfs_quota_on(sb, type, format_id, path, remount);
|
||||
return vfs_quota_on(sb, type, format_id, name, remount);
|
||||
|
||||
err = path_lookup(path, LOOKUP_FOLLOW, &nd);
|
||||
err = kern_path(name, LOOKUP_FOLLOW, &path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Quotafile not on the same filesystem? */
|
||||
if (nd.path.mnt->mnt_sb != sb) {
|
||||
path_put(&nd.path);
|
||||
if (path.mnt->mnt_sb != sb) {
|
||||
path_put(&path);
|
||||
return -EXDEV;
|
||||
}
|
||||
/* Journaling quota? */
|
||||
if (EXT3_SB(sb)->s_qf_names[type]) {
|
||||
/* Quotafile not of fs root? */
|
||||
if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode)
|
||||
if (path.dentry->d_parent != sb->s_root)
|
||||
printk(KERN_WARNING
|
||||
"EXT3-fs: Quota file not on filesystem root. "
|
||||
"Journaled quota will not work.\n");
|
||||
@ -2827,7 +2827,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
|
||||
* When we journal data on quota file, we have to flush journal to see
|
||||
* all updates to the file when we bypass pagecache...
|
||||
*/
|
||||
if (ext3_should_journal_data(nd.path.dentry->d_inode)) {
|
||||
if (ext3_should_journal_data(path.dentry->d_inode)) {
|
||||
/*
|
||||
* We don't need to lock updates but journal_flush() could
|
||||
* otherwise be livelocked...
|
||||
@ -2841,8 +2841,8 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
|
||||
}
|
||||
}
|
||||
|
||||
err = vfs_quota_on_path(sb, type, format_id, &nd.path);
|
||||
path_put(&nd.path);
|
||||
err = vfs_quota_on_path(sb, type, format_id, &path);
|
||||
path_put(&path);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1083,16 +1083,7 @@ struct dentry *ext4_get_parent(struct dentry *child)
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
inode = ext4_iget(child->d_inode->i_sb, ino);
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent) {
|
||||
iput(inode);
|
||||
parent = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return parent;
|
||||
return d_obtain_alias(ext4_iget(child->d_inode->i_sb, ino));
|
||||
}
|
||||
|
||||
#define S_SHIFT 12
|
||||
|
@ -3328,30 +3328,30 @@ static int ext4_quota_on_mount(struct super_block *sb, int type)
|
||||
* Standard function to be called on quota_on
|
||||
*/
|
||||
static int ext4_quota_on(struct super_block *sb, int type, int format_id,
|
||||
char *path, int remount)
|
||||
char *name, int remount)
|
||||
{
|
||||
int err;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
|
||||
if (!test_opt(sb, QUOTA))
|
||||
return -EINVAL;
|
||||
/* When remounting, no checks are needed and in fact, path is NULL */
|
||||
/* When remounting, no checks are needed and in fact, name is NULL */
|
||||
if (remount)
|
||||
return vfs_quota_on(sb, type, format_id, path, remount);
|
||||
return vfs_quota_on(sb, type, format_id, name, remount);
|
||||
|
||||
err = path_lookup(path, LOOKUP_FOLLOW, &nd);
|
||||
err = kern_path(name, LOOKUP_FOLLOW, &path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Quotafile not on the same filesystem? */
|
||||
if (nd.path.mnt->mnt_sb != sb) {
|
||||
path_put(&nd.path);
|
||||
if (path.mnt->mnt_sb != sb) {
|
||||
path_put(&path);
|
||||
return -EXDEV;
|
||||
}
|
||||
/* Journaling quota? */
|
||||
if (EXT4_SB(sb)->s_qf_names[type]) {
|
||||
/* Quotafile not in fs root? */
|
||||
if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode)
|
||||
if (path.dentry->d_parent != sb->s_root)
|
||||
printk(KERN_WARNING
|
||||
"EXT4-fs: Quota file not on filesystem root. "
|
||||
"Journaled quota will not work.\n");
|
||||
@ -3361,7 +3361,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
|
||||
* When we journal data on quota file, we have to flush journal to see
|
||||
* all updates to the file when we bypass pagecache...
|
||||
*/
|
||||
if (ext4_should_journal_data(nd.path.dentry->d_inode)) {
|
||||
if (ext4_should_journal_data(path.dentry->d_inode)) {
|
||||
/*
|
||||
* We don't need to lock updates but journal_flush() could
|
||||
* otherwise be livelocked...
|
||||
@ -3370,13 +3370,13 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
|
||||
err = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
|
||||
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
|
||||
if (err) {
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = vfs_quota_on_path(sb, type, format_id, &nd.path);
|
||||
path_put(&nd.path);
|
||||
err = vfs_quota_on_path(sb, type, format_id, &path);
|
||||
path_put(&path);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -839,6 +839,7 @@ const struct file_operations fat_dir_operations = {
|
||||
.compat_ioctl = fat_compat_dir_ioctl,
|
||||
#endif
|
||||
.fsync = file_fsync,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
static int fat_get_short_entry(struct inode *dir, loff_t *pos,
|
||||
|
@ -681,33 +681,24 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb,
|
||||
inode = NULL;
|
||||
}
|
||||
}
|
||||
if (!inode) {
|
||||
/* For now, do nothing
|
||||
* What we could do is:
|
||||
* follow the file starting at fh[4], and record
|
||||
* the ".." entry, and the name of the fh[2] entry.
|
||||
* The follow the ".." file finding the next step up.
|
||||
* This way we build a path to the root of
|
||||
* the tree. If this works, we lookup the path and so
|
||||
* get this inode into the cache.
|
||||
* Finally try the fat_iget lookup again
|
||||
* If that fails, then weare totally out of luck
|
||||
* But all that is for another day
|
||||
*/
|
||||
}
|
||||
if (!inode)
|
||||
return ERR_PTR(-ESTALE);
|
||||
|
||||
|
||||
/* now to find a dentry.
|
||||
* If possible, get a well-connected one
|
||||
/*
|
||||
* For now, do nothing if the inode is not found.
|
||||
*
|
||||
* What we could do is:
|
||||
*
|
||||
* - follow the file starting at fh[4], and record the ".." entry,
|
||||
* and the name of the fh[2] entry.
|
||||
* - then follow the ".." file finding the next step up.
|
||||
*
|
||||
* This way we build a path to the root of the tree. If this works, we
|
||||
* lookup the path and so get this inode into the cache. Finally try
|
||||
* the fat_iget lookup again. If that fails, then we are totally out
|
||||
* of luck. But all that is for another day
|
||||
*/
|
||||
result = d_alloc_anon(inode);
|
||||
if (result == NULL) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
result->d_op = sb->s_root->d_op;
|
||||
result = d_obtain_alias(inode);
|
||||
if (!IS_ERR(result))
|
||||
result->d_op = sb->s_root->d_op;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -754,15 +745,8 @@ static struct dentry *fat_get_parent(struct dentry *child)
|
||||
}
|
||||
inode = fat_build_inode(sb, de, i_pos);
|
||||
brelse(bh);
|
||||
if (IS_ERR(inode)) {
|
||||
parent = ERR_CAST(inode);
|
||||
goto out;
|
||||
}
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent) {
|
||||
iput(inode);
|
||||
parent = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
parent = d_obtain_alias(inode);
|
||||
out:
|
||||
unlock_super(sb);
|
||||
|
||||
|
@ -596,12 +596,8 @@ static struct dentry *fuse_get_dentry(struct super_block *sb,
|
||||
if (inode->i_generation != handle->generation)
|
||||
goto out_iput;
|
||||
|
||||
entry = d_alloc_anon(inode);
|
||||
err = -ENOMEM;
|
||||
if (!entry)
|
||||
goto out_iput;
|
||||
|
||||
if (get_node_id(inode) != FUSE_ROOT_ID) {
|
||||
entry = d_obtain_alias(inode);
|
||||
if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID) {
|
||||
entry->d_op = &fuse_dentry_operations;
|
||||
fuse_invalidate_entry_cache(entry);
|
||||
}
|
||||
@ -696,17 +692,14 @@ static struct dentry *fuse_get_parent(struct dentry *child)
|
||||
name.name = "..";
|
||||
err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode),
|
||||
&name, &outarg, &inode);
|
||||
if (err && err != -ENOENT)
|
||||
if (err) {
|
||||
if (err == -ENOENT)
|
||||
return ERR_PTR(-ESTALE);
|
||||
return ERR_PTR(err);
|
||||
if (err || !inode)
|
||||
return ERR_PTR(-ESTALE);
|
||||
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
if (get_node_id(inode) != FUSE_ROOT_ID) {
|
||||
|
||||
parent = d_obtain_alias(inode);
|
||||
if (!IS_ERR(parent) && get_node_id(inode) != FUSE_ROOT_ID) {
|
||||
parent->d_op = &fuse_dentry_operations;
|
||||
fuse_invalidate_entry_cache(parent);
|
||||
}
|
||||
|
@ -130,28 +130,17 @@ static int gfs2_get_name(struct dentry *parent, char *name,
|
||||
static struct dentry *gfs2_get_parent(struct dentry *child)
|
||||
{
|
||||
struct qstr dotdot;
|
||||
struct inode *inode;
|
||||
struct dentry *dentry;
|
||||
|
||||
gfs2_str2qstr(&dotdot, "..");
|
||||
inode = gfs2_lookupi(child->d_inode, &dotdot, 1);
|
||||
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOENT);
|
||||
/*
|
||||
* In case of an error, @inode carries the error value, and we
|
||||
* have to return that as a(n invalid) pointer to dentry.
|
||||
* XXX(hch): it would be a good idea to keep this around as a
|
||||
* static variable.
|
||||
*/
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
gfs2_str2qstr(&dotdot, "..");
|
||||
|
||||
dentry = d_alloc_anon(inode);
|
||||
if (!dentry) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
dentry->d_op = &gfs2_dops;
|
||||
dentry = d_obtain_alias(gfs2_lookupi(child->d_inode, &dotdot, 1));
|
||||
if (!IS_ERR(dentry))
|
||||
dentry->d_op = &gfs2_dops;
|
||||
return dentry;
|
||||
}
|
||||
|
||||
@ -233,13 +222,9 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
|
||||
out_inode:
|
||||
dentry = d_alloc_anon(inode);
|
||||
if (!dentry) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
dentry->d_op = &gfs2_dops;
|
||||
dentry = d_obtain_alias(inode);
|
||||
if (!IS_ERR(dentry))
|
||||
dentry->d_op = &gfs2_dops;
|
||||
return dentry;
|
||||
|
||||
fail_rgd:
|
||||
|
@ -69,7 +69,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
|
||||
mark_inode_dirty(inode);
|
||||
break;
|
||||
} else if (PTR_ERR(inode) != -EEXIST ||
|
||||
(nd && (nd->intent.open.flags & O_EXCL))) {
|
||||
(nd && nd->flags & LOOKUP_EXCL)) {
|
||||
gfs2_holder_uninit(ghs);
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
|
@ -511,13 +511,6 @@ void hfs_clear_inode(struct inode *inode)
|
||||
}
|
||||
}
|
||||
|
||||
static int hfs_permission(struct inode *inode, int mask)
|
||||
{
|
||||
if (S_ISREG(inode->i_mode) && mask & MAY_EXEC)
|
||||
return 0;
|
||||
return generic_permission(inode, mask, NULL);
|
||||
}
|
||||
|
||||
static int hfs_file_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (HFS_IS_RSRC(inode))
|
||||
@ -616,7 +609,6 @@ static const struct inode_operations hfs_file_inode_operations = {
|
||||
.lookup = hfs_file_lookup,
|
||||
.truncate = hfs_file_truncate,
|
||||
.setattr = hfs_inode_setattr,
|
||||
.permission = hfs_permission,
|
||||
.setxattr = hfs_setxattr,
|
||||
.getxattr = hfs_getxattr,
|
||||
.listxattr = hfs_listxattr,
|
||||
|
@ -238,18 +238,6 @@ static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
|
||||
perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
|
||||
}
|
||||
|
||||
static int hfsplus_permission(struct inode *inode, int mask)
|
||||
{
|
||||
/* MAY_EXEC is also used for lookup, if no x bit is set allow lookup,
|
||||
* open_exec has the same test, so it's still not executable, if a x bit
|
||||
* is set fall back to standard permission check.
|
||||
*/
|
||||
if (S_ISREG(inode->i_mode) && mask & MAY_EXEC && !(inode->i_mode & 0111))
|
||||
return 0;
|
||||
return generic_permission(inode, mask, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int hfsplus_file_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (HFSPLUS_IS_RSRC(inode))
|
||||
@ -281,7 +269,6 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
|
||||
static const struct inode_operations hfsplus_file_inode_operations = {
|
||||
.lookup = hfsplus_file_lookup,
|
||||
.truncate = hfsplus_file_truncate,
|
||||
.permission = hfsplus_permission,
|
||||
.setxattr = hfsplus_setxattr,
|
||||
.getxattr = hfsplus_getxattr,
|
||||
.listxattr = hfsplus_listxattr,
|
||||
|
@ -143,5 +143,5 @@ const struct file_operations hpfs_file_ops =
|
||||
const struct inode_operations hpfs_file_iops =
|
||||
{
|
||||
.truncate = hpfs_truncate,
|
||||
.setattr = hpfs_notify_change,
|
||||
.setattr = hpfs_setattr,
|
||||
};
|
||||
|
@ -275,7 +275,7 @@ void hpfs_init_inode(struct inode *);
|
||||
void hpfs_read_inode(struct inode *);
|
||||
void hpfs_write_inode(struct inode *);
|
||||
void hpfs_write_inode_nolock(struct inode *);
|
||||
int hpfs_notify_change(struct dentry *, struct iattr *);
|
||||
int hpfs_setattr(struct dentry *, struct iattr *);
|
||||
void hpfs_write_if_changed(struct inode *);
|
||||
void hpfs_delete_inode(struct inode *);
|
||||
|
||||
|
@ -260,19 +260,28 @@ void hpfs_write_inode_nolock(struct inode *i)
|
||||
brelse(bh);
|
||||
}
|
||||
|
||||
int hpfs_notify_change(struct dentry *dentry, struct iattr *attr)
|
||||
int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error=0;
|
||||
int error = -EINVAL;
|
||||
|
||||
lock_kernel();
|
||||
if ( ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) ||
|
||||
(hpfs_sb(inode->i_sb)->sb_root == inode->i_ino) ) {
|
||||
error = -EINVAL;
|
||||
} else if ((error = inode_change_ok(inode, attr))) {
|
||||
} else if ((error = inode_setattr(inode, attr))) {
|
||||
} else {
|
||||
hpfs_write_inode(inode);
|
||||
}
|
||||
if (inode->i_ino == hpfs_sb(inode->i_sb)->sb_root)
|
||||
goto out_unlock;
|
||||
if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size)
|
||||
goto out_unlock;
|
||||
|
||||
error = inode_change_ok(inode, attr);
|
||||
if (error)
|
||||
goto out_unlock;
|
||||
|
||||
error = inode_setattr(inode, attr);
|
||||
if (error)
|
||||
goto out_unlock;
|
||||
|
||||
hpfs_write_inode(inode);
|
||||
|
||||
out_unlock:
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
@ -669,5 +669,5 @@ const struct inode_operations hpfs_dir_iops =
|
||||
.rmdir = hpfs_rmdir,
|
||||
.mknod = hpfs_mknod,
|
||||
.rename = hpfs_rename,
|
||||
.setattr = hpfs_notify_change,
|
||||
.setattr = hpfs_setattr,
|
||||
};
|
||||
|
@ -22,7 +22,7 @@ isofs_export_iget(struct super_block *sb,
|
||||
__u32 generation)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dentry *result;
|
||||
|
||||
if (block == 0)
|
||||
return ERR_PTR(-ESTALE);
|
||||
inode = isofs_iget(sb, block, offset);
|
||||
@ -32,12 +32,7 @@ isofs_export_iget(struct super_block *sb,
|
||||
iput(inode);
|
||||
return ERR_PTR(-ESTALE);
|
||||
}
|
||||
result = d_alloc_anon(inode);
|
||||
if (!result) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return result;
|
||||
return d_obtain_alias(inode);
|
||||
}
|
||||
|
||||
/* This function is surprisingly simple. The trick is understanding
|
||||
@ -51,7 +46,6 @@ static struct dentry *isofs_export_get_parent(struct dentry *child)
|
||||
unsigned long parent_offset = 0;
|
||||
struct inode *child_inode = child->d_inode;
|
||||
struct iso_inode_info *e_child_inode = ISOFS_I(child_inode);
|
||||
struct inode *parent_inode = NULL;
|
||||
struct iso_directory_record *de = NULL;
|
||||
struct buffer_head * bh = NULL;
|
||||
struct dentry *rv = NULL;
|
||||
@ -104,28 +98,11 @@ static struct dentry *isofs_export_get_parent(struct dentry *child)
|
||||
/* Normalize */
|
||||
isofs_normalize_block_and_offset(de, &parent_block, &parent_offset);
|
||||
|
||||
/* Get the inode. */
|
||||
parent_inode = isofs_iget(child_inode->i_sb,
|
||||
parent_block,
|
||||
parent_offset);
|
||||
if (IS_ERR(parent_inode)) {
|
||||
rv = ERR_CAST(parent_inode);
|
||||
if (rv != ERR_PTR(-ENOMEM))
|
||||
rv = ERR_PTR(-EACCES);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Allocate the dentry. */
|
||||
rv = d_alloc_anon(parent_inode);
|
||||
if (rv == NULL) {
|
||||
rv = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = d_obtain_alias(isofs_iget(child_inode->i_sb, parent_block,
|
||||
parent_offset));
|
||||
out:
|
||||
if (bh) {
|
||||
if (bh)
|
||||
brelse(bh);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,8 @@ const struct file_operations jffs2_dir_operations =
|
||||
.read = generic_read_dir,
|
||||
.readdir = jffs2_readdir,
|
||||
.unlocked_ioctl=jffs2_ioctl,
|
||||
.fsync = jffs2_fsync
|
||||
.fsync = jffs2_fsync,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
|
||||
@ -108,9 +109,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
|
||||
}
|
||||
}
|
||||
|
||||
d_add(target, inode);
|
||||
|
||||
return NULL;
|
||||
return d_splice_alias(inode, target);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/mtd/super.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include "compr.h"
|
||||
#include "nodelist.h"
|
||||
|
||||
@ -62,6 +63,52 @@ static int jffs2_sync_fs(struct super_block *sb, int wait)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
|
||||
uint32_t generation)
|
||||
{
|
||||
/* We don't care about i_generation. We'll destroy the flash
|
||||
before we start re-using inode numbers anyway. And even
|
||||
if that wasn't true, we'd have other problems...*/
|
||||
return jffs2_iget(sb, ino);
|
||||
}
|
||||
|
||||
static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
|
||||
int fh_len, int fh_type)
|
||||
{
|
||||
return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
|
||||
jffs2_nfs_get_inode);
|
||||
}
|
||||
|
||||
static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
|
||||
int fh_len, int fh_type)
|
||||
{
|
||||
return generic_fh_to_parent(sb, fid, fh_len, fh_type,
|
||||
jffs2_nfs_get_inode);
|
||||
}
|
||||
|
||||
static struct dentry *jffs2_get_parent(struct dentry *child)
|
||||
{
|
||||
struct jffs2_inode_info *f;
|
||||
uint32_t pino;
|
||||
|
||||
BUG_ON(!S_ISDIR(child->d_inode->i_mode));
|
||||
|
||||
f = JFFS2_INODE_INFO(child->d_inode);
|
||||
|
||||
pino = f->inocache->pino_nlink;
|
||||
|
||||
JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
|
||||
f->inocache->ino, pino);
|
||||
|
||||
return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino));
|
||||
}
|
||||
|
||||
static struct export_operations jffs2_export_ops = {
|
||||
.get_parent = jffs2_get_parent,
|
||||
.fh_to_dentry = jffs2_fh_to_dentry,
|
||||
.fh_to_parent = jffs2_fh_to_parent,
|
||||
};
|
||||
|
||||
static const struct super_operations jffs2_super_operations =
|
||||
{
|
||||
.alloc_inode = jffs2_alloc_inode,
|
||||
@ -104,6 +151,7 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
|
||||
spin_lock_init(&c->inocache_lock);
|
||||
|
||||
sb->s_op = &jffs2_super_operations;
|
||||
sb->s_export_op = &jffs2_export_ops;
|
||||
sb->s_flags = sb->s_flags | MS_NOATIME;
|
||||
sb->s_xattr = jffs2_xattr_handlers;
|
||||
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
|
||||
|
@ -1511,25 +1511,12 @@ struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
|
||||
|
||||
struct dentry *jfs_get_parent(struct dentry *dentry)
|
||||
{
|
||||
struct super_block *sb = dentry->d_inode->i_sb;
|
||||
struct dentry *parent = ERR_PTR(-ENOENT);
|
||||
struct inode *inode;
|
||||
unsigned long parent_ino;
|
||||
|
||||
parent_ino =
|
||||
le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot);
|
||||
inode = jfs_iget(sb, parent_ino);
|
||||
if (IS_ERR(inode)) {
|
||||
parent = ERR_CAST(inode);
|
||||
} else {
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent) {
|
||||
parent = ERR_PTR(-ENOMEM);
|
||||
iput(inode);
|
||||
}
|
||||
}
|
||||
|
||||
return parent;
|
||||
return d_obtain_alias(jfs_iget(dentry->d_inode->i_sb, parent_ino));
|
||||
}
|
||||
|
||||
const struct inode_operations jfs_dir_inode_operations = {
|
||||
@ -1560,6 +1547,7 @@ const struct file_operations jfs_dir_operations = {
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = jfs_compat_ioctl,
|
||||
#endif
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
static int jfs_ci_hash(struct dentry *dir, struct qstr *this)
|
||||
|
26
fs/libfs.c
26
fs/libfs.c
@ -732,28 +732,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is what d_alloc_anon should have been. Once the exportfs
|
||||
* argument transition has been finished I will update d_alloc_anon
|
||||
* to this prototype and this wrapper will go away. --hch
|
||||
*/
|
||||
static struct dentry *exportfs_d_alloc(struct inode *inode)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
if (IS_ERR(inode))
|
||||
return ERR_PTR(PTR_ERR(inode));
|
||||
|
||||
dentry = d_alloc_anon(inode);
|
||||
if (!dentry) {
|
||||
iput(inode);
|
||||
dentry = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_fh_to_dentry - generic helper for the fh_to_dentry export operation
|
||||
* @sb: filesystem to do the file handle conversion on
|
||||
@ -782,7 +760,7 @@ struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid,
|
||||
break;
|
||||
}
|
||||
|
||||
return exportfs_d_alloc(inode);
|
||||
return d_obtain_alias(inode);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(generic_fh_to_dentry);
|
||||
|
||||
@ -815,7 +793,7 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
|
||||
break;
|
||||
}
|
||||
|
||||
return exportfs_d_alloc(inode);
|
||||
return d_obtain_alias(inode);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(generic_fh_to_parent);
|
||||
|
||||
|
156
fs/namei.c
156
fs/namei.c
@ -212,8 +212,7 @@ int generic_permission(struct inode *inode, int mask,
|
||||
* Read/write DACs are always overridable.
|
||||
* Executable DACs are overridable if at least one exec bit is set.
|
||||
*/
|
||||
if (!(mask & MAY_EXEC) ||
|
||||
(inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
|
||||
if (!(mask & MAY_EXEC) || execute_ok(inode))
|
||||
if (capable(CAP_DAC_OVERRIDE))
|
||||
return 0;
|
||||
|
||||
@ -249,23 +248,11 @@ int inode_permission(struct inode *inode, int mask)
|
||||
}
|
||||
|
||||
/* Ordinary permission routines do not understand MAY_APPEND. */
|
||||
if (inode->i_op && inode->i_op->permission) {
|
||||
if (inode->i_op && inode->i_op->permission)
|
||||
retval = inode->i_op->permission(inode, mask);
|
||||
if (!retval) {
|
||||
/*
|
||||
* Exec permission on a regular file is denied if none
|
||||
* of the execute bits are set.
|
||||
*
|
||||
* This check should be done by the ->permission()
|
||||
* method.
|
||||
*/
|
||||
if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) &&
|
||||
!(inode->i_mode & S_IXUGO))
|
||||
return -EACCES;
|
||||
}
|
||||
} else {
|
||||
else
|
||||
retval = generic_permission(inode, mask, NULL);
|
||||
}
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
@ -1106,6 +1093,15 @@ int path_lookup(const char *name, unsigned int flags,
|
||||
return do_path_lookup(AT_FDCWD, name, flags, nd);
|
||||
}
|
||||
|
||||
int kern_path(const char *name, unsigned int flags, struct path *path)
|
||||
{
|
||||
struct nameidata nd;
|
||||
int res = do_path_lookup(AT_FDCWD, name, flags, &nd);
|
||||
if (!res)
|
||||
*path = nd.path;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair
|
||||
* @dentry: pointer to dentry of the base directory
|
||||
@ -1138,29 +1134,6 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
|
||||
|
||||
}
|
||||
|
||||
static int __path_lookup_intent_open(int dfd, const char *name,
|
||||
unsigned int lookup_flags, struct nameidata *nd,
|
||||
int open_flags, int create_mode)
|
||||
{
|
||||
struct file *filp = get_empty_filp();
|
||||
int err;
|
||||
|
||||
if (filp == NULL)
|
||||
return -ENFILE;
|
||||
nd->intent.open.file = filp;
|
||||
nd->intent.open.flags = open_flags;
|
||||
nd->intent.open.create_mode = create_mode;
|
||||
err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd);
|
||||
if (IS_ERR(nd->intent.open.file)) {
|
||||
if (err == 0) {
|
||||
err = PTR_ERR(nd->intent.open.file);
|
||||
path_put(&nd->path);
|
||||
}
|
||||
} else if (err != 0)
|
||||
release_open_intent(nd);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_lookup_open - lookup a file path with open intent
|
||||
* @dfd: the directory to use as base, or AT_FDCWD
|
||||
@ -1172,25 +1145,23 @@ static int __path_lookup_intent_open(int dfd, const char *name,
|
||||
int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags,
|
||||
struct nameidata *nd, int open_flags)
|
||||
{
|
||||
return __path_lookup_intent_open(dfd, name, lookup_flags, nd,
|
||||
open_flags, 0);
|
||||
}
|
||||
struct file *filp = get_empty_filp();
|
||||
int err;
|
||||
|
||||
/**
|
||||
* path_lookup_create - lookup a file path with open + create intent
|
||||
* @dfd: the directory to use as base, or AT_FDCWD
|
||||
* @name: pointer to file name
|
||||
* @lookup_flags: lookup intent flags
|
||||
* @nd: pointer to nameidata
|
||||
* @open_flags: open intent flags
|
||||
* @create_mode: create intent flags
|
||||
*/
|
||||
static int path_lookup_create(int dfd, const char *name,
|
||||
unsigned int lookup_flags, struct nameidata *nd,
|
||||
int open_flags, int create_mode)
|
||||
{
|
||||
return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE,
|
||||
nd, open_flags, create_mode);
|
||||
if (filp == NULL)
|
||||
return -ENFILE;
|
||||
nd->intent.open.file = filp;
|
||||
nd->intent.open.flags = open_flags;
|
||||
nd->intent.open.create_mode = 0;
|
||||
err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd);
|
||||
if (IS_ERR(nd->intent.open.file)) {
|
||||
if (err == 0) {
|
||||
err = PTR_ERR(nd->intent.open.file);
|
||||
path_put(&nd->path);
|
||||
}
|
||||
} else if (err != 0)
|
||||
release_open_intent(nd);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct dentry *__lookup_hash(struct qstr *name,
|
||||
@ -1470,20 +1441,18 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
|
||||
|
||||
mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
|
||||
|
||||
for (p = p1; p->d_parent != p; p = p->d_parent) {
|
||||
if (p->d_parent == p2) {
|
||||
mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD);
|
||||
return p;
|
||||
}
|
||||
p = d_ancestor(p2, p1);
|
||||
if (p) {
|
||||
mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD);
|
||||
return p;
|
||||
}
|
||||
|
||||
for (p = p2; p->d_parent != p; p = p->d_parent) {
|
||||
if (p->d_parent == p1) {
|
||||
mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD);
|
||||
return p;
|
||||
}
|
||||
p = d_ancestor(p1, p2);
|
||||
if (p) {
|
||||
mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD);
|
||||
return p;
|
||||
}
|
||||
|
||||
mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
@ -1702,8 +1671,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
||||
/*
|
||||
* Create - we need to know the parent.
|
||||
*/
|
||||
error = path_lookup_create(dfd, pathname, LOOKUP_PARENT,
|
||||
&nd, flag, mode);
|
||||
error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
|
||||
@ -1714,10 +1682,20 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
||||
*/
|
||||
error = -EISDIR;
|
||||
if (nd.last_type != LAST_NORM || nd.last.name[nd.last.len])
|
||||
goto exit;
|
||||
goto exit_parent;
|
||||
|
||||
error = -ENFILE;
|
||||
filp = get_empty_filp();
|
||||
if (filp == NULL)
|
||||
goto exit_parent;
|
||||
nd.intent.open.file = filp;
|
||||
nd.intent.open.flags = flag;
|
||||
nd.intent.open.create_mode = mode;
|
||||
dir = nd.path.dentry;
|
||||
nd.flags &= ~LOOKUP_PARENT;
|
||||
nd.flags |= LOOKUP_CREATE | LOOKUP_OPEN;
|
||||
if (flag & O_EXCL)
|
||||
nd.flags |= LOOKUP_EXCL;
|
||||
mutex_lock(&dir->d_inode->i_mutex);
|
||||
path.dentry = lookup_hash(&nd);
|
||||
path.mnt = nd.path.mnt;
|
||||
@ -1822,6 +1800,7 @@ exit_dput:
|
||||
exit:
|
||||
if (!IS_ERR(nd.intent.open.file))
|
||||
release_open_intent(&nd);
|
||||
exit_parent:
|
||||
path_put(&nd.path);
|
||||
return ERR_PTR(error);
|
||||
|
||||
@ -1914,7 +1893,7 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
|
||||
if (nd->last_type != LAST_NORM)
|
||||
goto fail;
|
||||
nd->flags &= ~LOOKUP_PARENT;
|
||||
nd->flags |= LOOKUP_CREATE;
|
||||
nd->flags |= LOOKUP_CREATE | LOOKUP_EXCL;
|
||||
nd->intent.open.flags = O_EXCL;
|
||||
|
||||
/*
|
||||
@ -2178,16 +2157,19 @@ static long do_rmdir(int dfd, const char __user *pathname)
|
||||
return error;
|
||||
|
||||
switch(nd.last_type) {
|
||||
case LAST_DOTDOT:
|
||||
error = -ENOTEMPTY;
|
||||
goto exit1;
|
||||
case LAST_DOT:
|
||||
error = -EINVAL;
|
||||
goto exit1;
|
||||
case LAST_ROOT:
|
||||
error = -EBUSY;
|
||||
goto exit1;
|
||||
case LAST_DOTDOT:
|
||||
error = -ENOTEMPTY;
|
||||
goto exit1;
|
||||
case LAST_DOT:
|
||||
error = -EINVAL;
|
||||
goto exit1;
|
||||
case LAST_ROOT:
|
||||
error = -EBUSY;
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
nd.flags &= ~LOOKUP_PARENT;
|
||||
|
||||
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
dentry = lookup_hash(&nd);
|
||||
error = PTR_ERR(dentry);
|
||||
@ -2265,6 +2247,9 @@ static long do_unlinkat(int dfd, const char __user *pathname)
|
||||
error = -EISDIR;
|
||||
if (nd.last_type != LAST_NORM)
|
||||
goto exit1;
|
||||
|
||||
nd.flags &= ~LOOKUP_PARENT;
|
||||
|
||||
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
dentry = lookup_hash(&nd);
|
||||
error = PTR_ERR(dentry);
|
||||
@ -2654,6 +2639,10 @@ asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
|
||||
if (newnd.last_type != LAST_NORM)
|
||||
goto exit2;
|
||||
|
||||
oldnd.flags &= ~LOOKUP_PARENT;
|
||||
newnd.flags &= ~LOOKUP_PARENT;
|
||||
newnd.flags |= LOOKUP_RENAME_TARGET;
|
||||
|
||||
trap = lock_rename(new_dir, old_dir);
|
||||
|
||||
old_dentry = lookup_hash(&oldnd);
|
||||
@ -2855,6 +2844,7 @@ EXPORT_SYMBOL(__page_symlink);
|
||||
EXPORT_SYMBOL(page_symlink);
|
||||
EXPORT_SYMBOL(page_symlink_inode_operations);
|
||||
EXPORT_SYMBOL(path_lookup);
|
||||
EXPORT_SYMBOL(kern_path);
|
||||
EXPORT_SYMBOL(vfs_path_lookup);
|
||||
EXPORT_SYMBOL(inode_permission);
|
||||
EXPORT_SYMBOL(vfs_permission);
|
||||
|
133
fs/namespace.c
133
fs/namespace.c
@ -1167,19 +1167,19 @@ asmlinkage long sys_oldumount(char __user * name)
|
||||
|
||||
#endif
|
||||
|
||||
static int mount_is_safe(struct nameidata *nd)
|
||||
static int mount_is_safe(struct path *path)
|
||||
{
|
||||
if (capable(CAP_SYS_ADMIN))
|
||||
return 0;
|
||||
return -EPERM;
|
||||
#ifdef notyet
|
||||
if (S_ISLNK(nd->path.dentry->d_inode->i_mode))
|
||||
if (S_ISLNK(path->dentry->d_inode->i_mode))
|
||||
return -EPERM;
|
||||
if (nd->path.dentry->d_inode->i_mode & S_ISVTX) {
|
||||
if (current->uid != nd->path.dentry->d_inode->i_uid)
|
||||
if (path->dentry->d_inode->i_mode & S_ISVTX) {
|
||||
if (current->uid != path->dentry->d_inode->i_uid)
|
||||
return -EPERM;
|
||||
}
|
||||
if (vfs_permission(nd, MAY_WRITE))
|
||||
if (inode_permission(path->dentry->d_inode, MAY_WRITE))
|
||||
return -EPERM;
|
||||
return 0;
|
||||
#endif
|
||||
@ -1425,11 +1425,10 @@ out_unlock:
|
||||
|
||||
/*
|
||||
* recursively change the type of the mountpoint.
|
||||
* noinline this do_mount helper to save do_mount stack space.
|
||||
*/
|
||||
static noinline int do_change_type(struct nameidata *nd, int flag)
|
||||
static int do_change_type(struct path *path, int flag)
|
||||
{
|
||||
struct vfsmount *m, *mnt = nd->path.mnt;
|
||||
struct vfsmount *m, *mnt = path->mnt;
|
||||
int recurse = flag & MS_REC;
|
||||
int type = flag & ~MS_REC;
|
||||
int err = 0;
|
||||
@ -1437,7 +1436,7 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (nd->path.dentry != nd->path.mnt->mnt_root)
|
||||
if (path->dentry != path->mnt->mnt_root)
|
||||
return -EINVAL;
|
||||
|
||||
down_write(&namespace_sem);
|
||||
@ -1459,40 +1458,39 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
|
||||
|
||||
/*
|
||||
* do loopback mount.
|
||||
* noinline this do_mount helper to save do_mount stack space.
|
||||
*/
|
||||
static noinline int do_loopback(struct nameidata *nd, char *old_name,
|
||||
static int do_loopback(struct path *path, char *old_name,
|
||||
int recurse)
|
||||
{
|
||||
struct nameidata old_nd;
|
||||
struct path old_path;
|
||||
struct vfsmount *mnt = NULL;
|
||||
int err = mount_is_safe(nd);
|
||||
int err = mount_is_safe(path);
|
||||
if (err)
|
||||
return err;
|
||||
if (!old_name || !*old_name)
|
||||
return -EINVAL;
|
||||
err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd);
|
||||
err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
down_write(&namespace_sem);
|
||||
err = -EINVAL;
|
||||
if (IS_MNT_UNBINDABLE(old_nd.path.mnt))
|
||||
if (IS_MNT_UNBINDABLE(old_path.mnt))
|
||||
goto out;
|
||||
|
||||
if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt))
|
||||
if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
|
||||
goto out;
|
||||
|
||||
err = -ENOMEM;
|
||||
if (recurse)
|
||||
mnt = copy_tree(old_nd.path.mnt, old_nd.path.dentry, 0);
|
||||
mnt = copy_tree(old_path.mnt, old_path.dentry, 0);
|
||||
else
|
||||
mnt = clone_mnt(old_nd.path.mnt, old_nd.path.dentry, 0);
|
||||
mnt = clone_mnt(old_path.mnt, old_path.dentry, 0);
|
||||
|
||||
if (!mnt)
|
||||
goto out;
|
||||
|
||||
err = graft_tree(mnt, &nd->path);
|
||||
err = graft_tree(mnt, path);
|
||||
if (err) {
|
||||
LIST_HEAD(umount_list);
|
||||
spin_lock(&vfsmount_lock);
|
||||
@ -1503,7 +1501,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name,
|
||||
|
||||
out:
|
||||
up_write(&namespace_sem);
|
||||
path_put(&old_nd.path);
|
||||
path_put(&old_path);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1528,33 +1526,37 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
|
||||
* change filesystem flags. dir should be a physical root of filesystem.
|
||||
* If you've mounted a non-root directory somewhere and want to do remount
|
||||
* on it - tough luck.
|
||||
* noinline this do_mount helper to save do_mount stack space.
|
||||
*/
|
||||
static noinline int do_remount(struct nameidata *nd, int flags, int mnt_flags,
|
||||
static int do_remount(struct path *path, int flags, int mnt_flags,
|
||||
void *data)
|
||||
{
|
||||
int err;
|
||||
struct super_block *sb = nd->path.mnt->mnt_sb;
|
||||
struct super_block *sb = path->mnt->mnt_sb;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (!check_mnt(nd->path.mnt))
|
||||
if (!check_mnt(path->mnt))
|
||||
return -EINVAL;
|
||||
|
||||
if (nd->path.dentry != nd->path.mnt->mnt_root)
|
||||
if (path->dentry != path->mnt->mnt_root)
|
||||
return -EINVAL;
|
||||
|
||||
down_write(&sb->s_umount);
|
||||
if (flags & MS_BIND)
|
||||
err = change_mount_flags(nd->path.mnt, flags);
|
||||
err = change_mount_flags(path->mnt, flags);
|
||||
else
|
||||
err = do_remount_sb(sb, flags, data, 0);
|
||||
if (!err)
|
||||
nd->path.mnt->mnt_flags = mnt_flags;
|
||||
path->mnt->mnt_flags = mnt_flags;
|
||||
up_write(&sb->s_umount);
|
||||
if (!err)
|
||||
security_sb_post_remount(nd->path.mnt, flags, data);
|
||||
if (!err) {
|
||||
security_sb_post_remount(path->mnt, flags, data);
|
||||
|
||||
spin_lock(&vfsmount_lock);
|
||||
touch_mnt_namespace(path->mnt->mnt_ns);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1568,90 +1570,85 @@ static inline int tree_contains_unbindable(struct vfsmount *mnt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* noinline this do_mount helper to save do_mount stack space.
|
||||
*/
|
||||
static noinline int do_move_mount(struct nameidata *nd, char *old_name)
|
||||
static int do_move_mount(struct path *path, char *old_name)
|
||||
{
|
||||
struct nameidata old_nd;
|
||||
struct path parent_path;
|
||||
struct path old_path, parent_path;
|
||||
struct vfsmount *p;
|
||||
int err = 0;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
if (!old_name || !*old_name)
|
||||
return -EINVAL;
|
||||
err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd);
|
||||
err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
down_write(&namespace_sem);
|
||||
while (d_mountpoint(nd->path.dentry) &&
|
||||
follow_down(&nd->path.mnt, &nd->path.dentry))
|
||||
while (d_mountpoint(path->dentry) &&
|
||||
follow_down(&path->mnt, &path->dentry))
|
||||
;
|
||||
err = -EINVAL;
|
||||
if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt))
|
||||
if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
|
||||
goto out;
|
||||
|
||||
err = -ENOENT;
|
||||
mutex_lock(&nd->path.dentry->d_inode->i_mutex);
|
||||
if (IS_DEADDIR(nd->path.dentry->d_inode))
|
||||
mutex_lock(&path->dentry->d_inode->i_mutex);
|
||||
if (IS_DEADDIR(path->dentry->d_inode))
|
||||
goto out1;
|
||||
|
||||
if (!IS_ROOT(nd->path.dentry) && d_unhashed(nd->path.dentry))
|
||||
if (!IS_ROOT(path->dentry) && d_unhashed(path->dentry))
|
||||
goto out1;
|
||||
|
||||
err = -EINVAL;
|
||||
if (old_nd.path.dentry != old_nd.path.mnt->mnt_root)
|
||||
if (old_path.dentry != old_path.mnt->mnt_root)
|
||||
goto out1;
|
||||
|
||||
if (old_nd.path.mnt == old_nd.path.mnt->mnt_parent)
|
||||
if (old_path.mnt == old_path.mnt->mnt_parent)
|
||||
goto out1;
|
||||
|
||||
if (S_ISDIR(nd->path.dentry->d_inode->i_mode) !=
|
||||
S_ISDIR(old_nd.path.dentry->d_inode->i_mode))
|
||||
if (S_ISDIR(path->dentry->d_inode->i_mode) !=
|
||||
S_ISDIR(old_path.dentry->d_inode->i_mode))
|
||||
goto out1;
|
||||
/*
|
||||
* Don't move a mount residing in a shared parent.
|
||||
*/
|
||||
if (old_nd.path.mnt->mnt_parent &&
|
||||
IS_MNT_SHARED(old_nd.path.mnt->mnt_parent))
|
||||
if (old_path.mnt->mnt_parent &&
|
||||
IS_MNT_SHARED(old_path.mnt->mnt_parent))
|
||||
goto out1;
|
||||
/*
|
||||
* Don't move a mount tree containing unbindable mounts to a destination
|
||||
* mount which is shared.
|
||||
*/
|
||||
if (IS_MNT_SHARED(nd->path.mnt) &&
|
||||
tree_contains_unbindable(old_nd.path.mnt))
|
||||
if (IS_MNT_SHARED(path->mnt) &&
|
||||
tree_contains_unbindable(old_path.mnt))
|
||||
goto out1;
|
||||
err = -ELOOP;
|
||||
for (p = nd->path.mnt; p->mnt_parent != p; p = p->mnt_parent)
|
||||
if (p == old_nd.path.mnt)
|
||||
for (p = path->mnt; p->mnt_parent != p; p = p->mnt_parent)
|
||||
if (p == old_path.mnt)
|
||||
goto out1;
|
||||
|
||||
err = attach_recursive_mnt(old_nd.path.mnt, &nd->path, &parent_path);
|
||||
err = attach_recursive_mnt(old_path.mnt, path, &parent_path);
|
||||
if (err)
|
||||
goto out1;
|
||||
|
||||
/* if the mount is moved, it should no longer be expire
|
||||
* automatically */
|
||||
list_del_init(&old_nd.path.mnt->mnt_expire);
|
||||
list_del_init(&old_path.mnt->mnt_expire);
|
||||
out1:
|
||||
mutex_unlock(&nd->path.dentry->d_inode->i_mutex);
|
||||
mutex_unlock(&path->dentry->d_inode->i_mutex);
|
||||
out:
|
||||
up_write(&namespace_sem);
|
||||
if (!err)
|
||||
path_put(&parent_path);
|
||||
path_put(&old_nd.path);
|
||||
path_put(&old_path);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* create a new mount for userspace and request it to be added into the
|
||||
* namespace's tree
|
||||
* noinline this do_mount helper to save do_mount stack space.
|
||||
*/
|
||||
static noinline int do_new_mount(struct nameidata *nd, char *type, int flags,
|
||||
static int do_new_mount(struct path *path, char *type, int flags,
|
||||
int mnt_flags, char *name, void *data)
|
||||
{
|
||||
struct vfsmount *mnt;
|
||||
@ -1667,7 +1664,7 @@ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags,
|
||||
if (IS_ERR(mnt))
|
||||
return PTR_ERR(mnt);
|
||||
|
||||
return do_add_mount(mnt, &nd->path, mnt_flags, NULL);
|
||||
return do_add_mount(mnt, path, mnt_flags, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1902,7 +1899,7 @@ int copy_mount_options(const void __user * data, unsigned long *where)
|
||||
long do_mount(char *dev_name, char *dir_name, char *type_page,
|
||||
unsigned long flags, void *data_page)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int retval = 0;
|
||||
int mnt_flags = 0;
|
||||
|
||||
@ -1940,29 +1937,29 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
|
||||
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT);
|
||||
|
||||
/* ... and get the mountpoint */
|
||||
retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd);
|
||||
retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = security_sb_mount(dev_name, &nd.path,
|
||||
retval = security_sb_mount(dev_name, &path,
|
||||
type_page, flags, data_page);
|
||||
if (retval)
|
||||
goto dput_out;
|
||||
|
||||
if (flags & MS_REMOUNT)
|
||||
retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
|
||||
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
|
||||
data_page);
|
||||
else if (flags & MS_BIND)
|
||||
retval = do_loopback(&nd, dev_name, flags & MS_REC);
|
||||
retval = do_loopback(&path, dev_name, flags & MS_REC);
|
||||
else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
|
||||
retval = do_change_type(&nd, flags);
|
||||
retval = do_change_type(&path, flags);
|
||||
else if (flags & MS_MOVE)
|
||||
retval = do_move_mount(&nd, dev_name);
|
||||
retval = do_move_mount(&path, dev_name);
|
||||
else
|
||||
retval = do_new_mount(&nd, type_page, flags, mnt_flags,
|
||||
retval = do_new_mount(&path, type_page, flags, mnt_flags,
|
||||
dev_name, data_page);
|
||||
dput_out:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -707,9 +707,7 @@ static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
|
||||
{
|
||||
if (NFS_PROTO(dir)->version == 2)
|
||||
return 0;
|
||||
if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
|
||||
return 0;
|
||||
return (nd->intent.open.flags & O_EXCL) != 0;
|
||||
return nd && nfs_lookup_check_intent(nd, LOOKUP_EXCL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1009,7 +1007,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
|
||||
|
||||
/* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
|
||||
* the dentry. */
|
||||
if (nd->intent.open.flags & O_EXCL) {
|
||||
if (nd->flags & LOOKUP_EXCL) {
|
||||
d_instantiate(dentry, NULL);
|
||||
goto out;
|
||||
}
|
||||
@ -1959,6 +1957,9 @@ force_lookup:
|
||||
} else
|
||||
res = PTR_ERR(cred);
|
||||
out:
|
||||
if (!res && (mask & MAY_EXEC) && !execute_ok(inode))
|
||||
res = -EACCES;
|
||||
|
||||
dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n",
|
||||
inode->i_sb->s_id, inode->i_ino, mask, res);
|
||||
return res;
|
||||
|
@ -107,11 +107,10 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
||||
* if the dentry tree reaches them; however if the dentry already
|
||||
* exists, we'll pick it up at this point and use it as the root
|
||||
*/
|
||||
mntroot = d_alloc_anon(inode);
|
||||
if (!mntroot) {
|
||||
iput(inode);
|
||||
mntroot = d_obtain_alias(inode);
|
||||
if (IS_ERR(mntroot)) {
|
||||
dprintk("nfs_get_root: get root dentry failed\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return mntroot;
|
||||
}
|
||||
|
||||
security_d_instantiate(mntroot, inode);
|
||||
@ -277,11 +276,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
||||
* if the dentry tree reaches them; however if the dentry already
|
||||
* exists, we'll pick it up at this point and use it as the root
|
||||
*/
|
||||
mntroot = d_alloc_anon(inode);
|
||||
if (!mntroot) {
|
||||
iput(inode);
|
||||
mntroot = d_obtain_alias(inode);
|
||||
if (IS_ERR(mntroot)) {
|
||||
dprintk("nfs_get_root: get root dentry failed\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return mntroot;
|
||||
}
|
||||
|
||||
security_d_instantiate(mntroot, inode);
|
||||
|
125
fs/nfsd/export.c
125
fs/nfsd/export.c
@ -163,18 +163,16 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
|
||||
if (!ek)
|
||||
err = -ENOMEM;
|
||||
} else {
|
||||
struct nameidata nd;
|
||||
err = path_lookup(buf, 0, &nd);
|
||||
err = kern_path(buf, 0, &key.ek_path);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
dprintk("Found the path %s\n", buf);
|
||||
key.ek_path = nd.path;
|
||||
|
||||
ek = svc_expkey_update(&key, ek);
|
||||
if (!ek)
|
||||
err = -ENOMEM;
|
||||
path_put(&nd.path);
|
||||
path_put(&key.ek_path);
|
||||
}
|
||||
cache_flush();
|
||||
out:
|
||||
@ -501,35 +499,22 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
|
||||
int len;
|
||||
int err;
|
||||
struct auth_domain *dom = NULL;
|
||||
struct nameidata nd;
|
||||
struct svc_export exp, *expp;
|
||||
struct svc_export exp = {}, *expp;
|
||||
int an_int;
|
||||
|
||||
nd.path.dentry = NULL;
|
||||
exp.ex_pathname = NULL;
|
||||
|
||||
/* fs locations */
|
||||
exp.ex_fslocs.locations = NULL;
|
||||
exp.ex_fslocs.locations_count = 0;
|
||||
exp.ex_fslocs.migrated = 0;
|
||||
|
||||
exp.ex_uuid = NULL;
|
||||
|
||||
/* secinfo */
|
||||
exp.ex_nflavors = 0;
|
||||
|
||||
if (mesg[mlen-1] != '\n')
|
||||
return -EINVAL;
|
||||
mesg[mlen-1] = 0;
|
||||
|
||||
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
err = -ENOMEM;
|
||||
if (!buf) goto out;
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* client */
|
||||
len = qword_get(&mesg, buf, PAGE_SIZE);
|
||||
err = -EINVAL;
|
||||
if (len <= 0) goto out;
|
||||
len = qword_get(&mesg, buf, PAGE_SIZE);
|
||||
if (len <= 0)
|
||||
goto out;
|
||||
|
||||
err = -ENOENT;
|
||||
dom = auth_domain_find(buf);
|
||||
@ -538,25 +523,25 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
|
||||
|
||||
/* path */
|
||||
err = -EINVAL;
|
||||
if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
|
||||
goto out;
|
||||
err = path_lookup(buf, 0, &nd);
|
||||
if (err) goto out_no_path;
|
||||
if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
|
||||
goto out1;
|
||||
|
||||
err = kern_path(buf, 0, &exp.ex_path);
|
||||
if (err)
|
||||
goto out1;
|
||||
|
||||
exp.h.flags = 0;
|
||||
exp.ex_client = dom;
|
||||
exp.ex_path.mnt = nd.path.mnt;
|
||||
exp.ex_path.dentry = nd.path.dentry;
|
||||
exp.ex_pathname = kstrdup(buf, GFP_KERNEL);
|
||||
|
||||
err = -ENOMEM;
|
||||
exp.ex_pathname = kstrdup(buf, GFP_KERNEL);
|
||||
if (!exp.ex_pathname)
|
||||
goto out;
|
||||
goto out2;
|
||||
|
||||
/* expiry */
|
||||
err = -EINVAL;
|
||||
exp.h.expiry_time = get_expiry(&mesg);
|
||||
if (exp.h.expiry_time == 0)
|
||||
goto out;
|
||||
goto out3;
|
||||
|
||||
/* flags */
|
||||
err = get_int(&mesg, &an_int);
|
||||
@ -564,22 +549,26 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
|
||||
err = 0;
|
||||
set_bit(CACHE_NEGATIVE, &exp.h.flags);
|
||||
} else {
|
||||
if (err || an_int < 0) goto out;
|
||||
if (err || an_int < 0)
|
||||
goto out3;
|
||||
exp.ex_flags= an_int;
|
||||
|
||||
/* anon uid */
|
||||
err = get_int(&mesg, &an_int);
|
||||
if (err) goto out;
|
||||
if (err)
|
||||
goto out3;
|
||||
exp.ex_anon_uid= an_int;
|
||||
|
||||
/* anon gid */
|
||||
err = get_int(&mesg, &an_int);
|
||||
if (err) goto out;
|
||||
if (err)
|
||||
goto out3;
|
||||
exp.ex_anon_gid= an_int;
|
||||
|
||||
/* fsid */
|
||||
err = get_int(&mesg, &an_int);
|
||||
if (err) goto out;
|
||||
if (err)
|
||||
goto out3;
|
||||
exp.ex_fsid = an_int;
|
||||
|
||||
while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
|
||||
@ -605,12 +594,13 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
|
||||
*/
|
||||
break;
|
||||
if (err)
|
||||
goto out;
|
||||
goto out4;
|
||||
}
|
||||
|
||||
err = check_export(nd.path.dentry->d_inode, exp.ex_flags,
|
||||
err = check_export(exp.ex_path.dentry->d_inode, exp.ex_flags,
|
||||
exp.ex_uuid);
|
||||
if (err) goto out;
|
||||
if (err)
|
||||
goto out4;
|
||||
}
|
||||
|
||||
expp = svc_export_lookup(&exp);
|
||||
@ -623,15 +613,16 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
|
||||
err = -ENOMEM;
|
||||
else
|
||||
exp_put(expp);
|
||||
out:
|
||||
out4:
|
||||
nfsd4_fslocs_free(&exp.ex_fslocs);
|
||||
kfree(exp.ex_uuid);
|
||||
out3:
|
||||
kfree(exp.ex_pathname);
|
||||
if (nd.path.dentry)
|
||||
path_put(&nd.path);
|
||||
out_no_path:
|
||||
if (dom)
|
||||
auth_domain_put(dom);
|
||||
out2:
|
||||
path_put(&exp.ex_path);
|
||||
out1:
|
||||
auth_domain_put(dom);
|
||||
out:
|
||||
kfree(buf);
|
||||
return err;
|
||||
}
|
||||
@ -999,7 +990,7 @@ exp_export(struct nfsctl_export *nxp)
|
||||
struct svc_export *exp = NULL;
|
||||
struct svc_export new;
|
||||
struct svc_expkey *fsid_key = NULL;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int err;
|
||||
|
||||
/* Consistency check */
|
||||
@ -1022,12 +1013,12 @@ exp_export(struct nfsctl_export *nxp)
|
||||
|
||||
|
||||
/* Look up the dentry */
|
||||
err = path_lookup(nxp->ex_path, 0, &nd);
|
||||
err = kern_path(nxp->ex_path, 0, &path);
|
||||
if (err)
|
||||
goto out_put_clp;
|
||||
err = -EINVAL;
|
||||
|
||||
exp = exp_get_by_name(clp, nd.path.mnt, nd.path.dentry, NULL);
|
||||
exp = exp_get_by_name(clp, path.mnt, path.dentry, NULL);
|
||||
|
||||
memset(&new, 0, sizeof(new));
|
||||
|
||||
@ -1035,8 +1026,8 @@ exp_export(struct nfsctl_export *nxp)
|
||||
if ((nxp->ex_flags & NFSEXP_FSID) &&
|
||||
(!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
|
||||
fsid_key->ek_path.mnt &&
|
||||
(fsid_key->ek_path.mnt != nd.path.mnt ||
|
||||
fsid_key->ek_path.dentry != nd.path.dentry))
|
||||
(fsid_key->ek_path.mnt != path.mnt ||
|
||||
fsid_key->ek_path.dentry != path.dentry))
|
||||
goto finish;
|
||||
|
||||
if (!IS_ERR(exp)) {
|
||||
@ -1052,7 +1043,7 @@ exp_export(struct nfsctl_export *nxp)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
err = check_export(nd.path.dentry->d_inode, nxp->ex_flags, NULL);
|
||||
err = check_export(path.dentry->d_inode, nxp->ex_flags, NULL);
|
||||
if (err) goto finish;
|
||||
|
||||
err = -ENOMEM;
|
||||
@ -1065,7 +1056,7 @@ exp_export(struct nfsctl_export *nxp)
|
||||
if (!new.ex_pathname)
|
||||
goto finish;
|
||||
new.ex_client = clp;
|
||||
new.ex_path = nd.path;
|
||||
new.ex_path = path;
|
||||
new.ex_flags = nxp->ex_flags;
|
||||
new.ex_anon_uid = nxp->ex_anon_uid;
|
||||
new.ex_anon_gid = nxp->ex_anon_gid;
|
||||
@ -1091,7 +1082,7 @@ finish:
|
||||
exp_put(exp);
|
||||
if (fsid_key && !IS_ERR(fsid_key))
|
||||
cache_put(&fsid_key->h, &svc_expkey_cache);
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out_put_clp:
|
||||
auth_domain_put(clp);
|
||||
out_unlock:
|
||||
@ -1122,7 +1113,7 @@ exp_unexport(struct nfsctl_export *nxp)
|
||||
{
|
||||
struct auth_domain *dom;
|
||||
svc_export *exp;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int err;
|
||||
|
||||
/* Consistency check */
|
||||
@ -1139,13 +1130,13 @@ exp_unexport(struct nfsctl_export *nxp)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
err = path_lookup(nxp->ex_path, 0, &nd);
|
||||
err = kern_path(nxp->ex_path, 0, &path);
|
||||
if (err)
|
||||
goto out_domain;
|
||||
|
||||
err = -EINVAL;
|
||||
exp = exp_get_by_name(dom, nd.path.mnt, nd.path.dentry, NULL);
|
||||
path_put(&nd.path);
|
||||
exp = exp_get_by_name(dom, path.mnt, path.dentry, NULL);
|
||||
path_put(&path);
|
||||
if (IS_ERR(exp))
|
||||
goto out_domain;
|
||||
|
||||
@ -1167,26 +1158,26 @@ out_unlock:
|
||||
* since its harder to fool a kernel module than a user space program.
|
||||
*/
|
||||
int
|
||||
exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
|
||||
exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
|
||||
{
|
||||
struct svc_export *exp;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
struct inode *inode;
|
||||
struct svc_fh fh;
|
||||
int err;
|
||||
|
||||
err = -EPERM;
|
||||
/* NB: we probably ought to check that it's NUL-terminated */
|
||||
if (path_lookup(path, 0, &nd)) {
|
||||
printk("nfsd: exp_rootfh path not found %s", path);
|
||||
if (kern_path(name, 0, &path)) {
|
||||
printk("nfsd: exp_rootfh path not found %s", name);
|
||||
return err;
|
||||
}
|
||||
inode = nd.path.dentry->d_inode;
|
||||
inode = path.dentry->d_inode;
|
||||
|
||||
dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
|
||||
path, nd.path.dentry, clp->name,
|
||||
name, path.dentry, clp->name,
|
||||
inode->i_sb->s_id, inode->i_ino);
|
||||
exp = exp_parent(clp, nd.path.mnt, nd.path.dentry, NULL);
|
||||
exp = exp_parent(clp, path.mnt, path.dentry, NULL);
|
||||
if (IS_ERR(exp)) {
|
||||
err = PTR_ERR(exp);
|
||||
goto out;
|
||||
@ -1196,7 +1187,7 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
|
||||
* fh must be initialized before calling fh_compose
|
||||
*/
|
||||
fh_init(&fh, maxsize);
|
||||
if (fh_compose(&fh, exp, nd.path.dentry, NULL))
|
||||
if (fh_compose(&fh, exp, path.dentry, NULL))
|
||||
err = -EINVAL;
|
||||
else
|
||||
err = 0;
|
||||
@ -1204,7 +1195,7 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
|
||||
fh_put(&fh);
|
||||
exp_put(exp);
|
||||
out:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
/* Globals */
|
||||
static struct nameidata rec_dir;
|
||||
static struct path rec_dir;
|
||||
static int rec_dir_init = 0;
|
||||
|
||||
static void
|
||||
@ -121,9 +121,9 @@ out_no_tfm:
|
||||
static void
|
||||
nfsd4_sync_rec_dir(void)
|
||||
{
|
||||
mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex);
|
||||
nfsd_sync_dir(rec_dir.path.dentry);
|
||||
mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex);
|
||||
mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
|
||||
nfsd_sync_dir(rec_dir.dentry);
|
||||
mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
|
||||
}
|
||||
|
||||
int
|
||||
@ -143,9 +143,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
|
||||
nfs4_save_user(&uid, &gid);
|
||||
|
||||
/* lock the parent */
|
||||
mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex);
|
||||
mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
|
||||
|
||||
dentry = lookup_one_len(dname, rec_dir.path.dentry, HEXDIR_LEN-1);
|
||||
dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1);
|
||||
if (IS_ERR(dentry)) {
|
||||
status = PTR_ERR(dentry);
|
||||
goto out_unlock;
|
||||
@ -155,15 +155,15 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
|
||||
dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n");
|
||||
goto out_put;
|
||||
}
|
||||
status = mnt_want_write(rec_dir.path.mnt);
|
||||
status = mnt_want_write(rec_dir.mnt);
|
||||
if (status)
|
||||
goto out_put;
|
||||
status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, S_IRWXU);
|
||||
mnt_drop_write(rec_dir.path.mnt);
|
||||
status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU);
|
||||
mnt_drop_write(rec_dir.mnt);
|
||||
out_put:
|
||||
dput(dentry);
|
||||
out_unlock:
|
||||
mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex);
|
||||
mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
|
||||
if (status == 0) {
|
||||
clp->cl_firststate = 1;
|
||||
nfsd4_sync_rec_dir();
|
||||
@ -226,7 +226,7 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
|
||||
|
||||
nfs4_save_user(&uid, &gid);
|
||||
|
||||
filp = dentry_open(dget(dir), mntget(rec_dir.path.mnt), O_RDONLY);
|
||||
filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY);
|
||||
status = PTR_ERR(filp);
|
||||
if (IS_ERR(filp))
|
||||
goto out;
|
||||
@ -291,9 +291,9 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
|
||||
|
||||
dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
|
||||
|
||||
mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex);
|
||||
dentry = lookup_one_len(name, rec_dir.path.dentry, namlen);
|
||||
mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex);
|
||||
mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
|
||||
dentry = lookup_one_len(name, rec_dir.dentry, namlen);
|
||||
mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
|
||||
if (IS_ERR(dentry)) {
|
||||
status = PTR_ERR(dentry);
|
||||
return status;
|
||||
@ -302,7 +302,7 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
|
||||
if (!dentry->d_inode)
|
||||
goto out;
|
||||
|
||||
status = nfsd4_clear_clid_dir(rec_dir.path.dentry, dentry);
|
||||
status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry);
|
||||
out:
|
||||
dput(dentry);
|
||||
return status;
|
||||
@ -318,7 +318,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
|
||||
if (!rec_dir_init || !clp->cl_firststate)
|
||||
return;
|
||||
|
||||
status = mnt_want_write(rec_dir.path.mnt);
|
||||
status = mnt_want_write(rec_dir.mnt);
|
||||
if (status)
|
||||
goto out;
|
||||
clp->cl_firststate = 0;
|
||||
@ -327,7 +327,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
|
||||
nfs4_reset_user(uid, gid);
|
||||
if (status == 0)
|
||||
nfsd4_sync_rec_dir();
|
||||
mnt_drop_write(rec_dir.path.mnt);
|
||||
mnt_drop_write(rec_dir.mnt);
|
||||
out:
|
||||
if (status)
|
||||
printk("NFSD: Failed to remove expired client state directory"
|
||||
@ -357,17 +357,17 @@ nfsd4_recdir_purge_old(void) {
|
||||
|
||||
if (!rec_dir_init)
|
||||
return;
|
||||
status = mnt_want_write(rec_dir.path.mnt);
|
||||
status = mnt_want_write(rec_dir.mnt);
|
||||
if (status)
|
||||
goto out;
|
||||
status = nfsd4_list_rec_dir(rec_dir.path.dentry, purge_old);
|
||||
status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old);
|
||||
if (status == 0)
|
||||
nfsd4_sync_rec_dir();
|
||||
mnt_drop_write(rec_dir.path.mnt);
|
||||
mnt_drop_write(rec_dir.mnt);
|
||||
out:
|
||||
if (status)
|
||||
printk("nfsd4: failed to purge old clients from recovery"
|
||||
" directory %s\n", rec_dir.path.dentry->d_name.name);
|
||||
" directory %s\n", rec_dir.dentry->d_name.name);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -387,10 +387,10 @@ int
|
||||
nfsd4_recdir_load(void) {
|
||||
int status;
|
||||
|
||||
status = nfsd4_list_rec_dir(rec_dir.path.dentry, load_recdir);
|
||||
status = nfsd4_list_rec_dir(rec_dir.dentry, load_recdir);
|
||||
if (status)
|
||||
printk("nfsd4: failed loading clients from recovery"
|
||||
" directory %s\n", rec_dir.path.dentry->d_name.name);
|
||||
" directory %s\n", rec_dir.dentry->d_name.name);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -412,7 +412,7 @@ nfsd4_init_recdir(char *rec_dirname)
|
||||
|
||||
nfs4_save_user(&uid, &gid);
|
||||
|
||||
status = path_lookup(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
|
||||
status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
|
||||
&rec_dir);
|
||||
if (status)
|
||||
printk("NFSD: unable to find recovery directory %s\n",
|
||||
@ -429,5 +429,5 @@ nfsd4_shutdown_recdir(void)
|
||||
if (!rec_dir_init)
|
||||
return;
|
||||
rec_dir_init = 0;
|
||||
path_put(&rec_dir.path);
|
||||
path_put(&rec_dir);
|
||||
}
|
||||
|
@ -3284,17 +3284,17 @@ int
|
||||
nfs4_reset_recoverydir(char *recdir)
|
||||
{
|
||||
int status;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
|
||||
status = path_lookup(recdir, LOOKUP_FOLLOW, &nd);
|
||||
status = kern_path(recdir, LOOKUP_FOLLOW, &path);
|
||||
if (status)
|
||||
return status;
|
||||
status = -ENOTDIR;
|
||||
if (S_ISDIR(nd.path.dentry->d_inode->i_mode)) {
|
||||
if (S_ISDIR(path.dentry->d_inode->i_mode)) {
|
||||
nfs4_set_recdir(recdir);
|
||||
status = 0;
|
||||
}
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -341,7 +341,7 @@ static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
|
||||
|
||||
static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
char *fo_path;
|
||||
int error;
|
||||
|
||||
@ -356,13 +356,13 @@ static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size)
|
||||
if (qword_get(&buf, fo_path, size) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
error = path_lookup(fo_path, 0, &nd);
|
||||
error = kern_path(fo_path, 0, &path);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = nlmsvc_unlock_all_by_sb(nd.path.mnt->mnt_sb);
|
||||
error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
|
||||
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
126
fs/nfsd/vfs.c
126
fs/nfsd/vfs.c
@ -1817,6 +1817,115 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* We do this buffering because we must not call back into the file
|
||||
* system's ->lookup() method from the filldir callback. That may well
|
||||
* deadlock a number of file systems.
|
||||
*
|
||||
* This is based heavily on the implementation of same in XFS.
|
||||
*/
|
||||
struct buffered_dirent {
|
||||
u64 ino;
|
||||
loff_t offset;
|
||||
int namlen;
|
||||
unsigned int d_type;
|
||||
char name[];
|
||||
};
|
||||
|
||||
struct readdir_data {
|
||||
char *dirent;
|
||||
size_t used;
|
||||
int full;
|
||||
};
|
||||
|
||||
static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
struct readdir_data *buf = __buf;
|
||||
struct buffered_dirent *de = (void *)(buf->dirent + buf->used);
|
||||
unsigned int reclen;
|
||||
|
||||
reclen = ALIGN(sizeof(struct buffered_dirent) + namlen, sizeof(u64));
|
||||
if (buf->used + reclen > PAGE_SIZE) {
|
||||
buf->full = 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
de->namlen = namlen;
|
||||
de->offset = offset;
|
||||
de->ino = ino;
|
||||
de->d_type = d_type;
|
||||
memcpy(de->name, name, namlen);
|
||||
buf->used += reclen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfsd_buffered_readdir(struct file *file, filldir_t func,
|
||||
struct readdir_cd *cdp, loff_t *offsetp)
|
||||
{
|
||||
struct readdir_data buf;
|
||||
struct buffered_dirent *de;
|
||||
int host_err;
|
||||
int size;
|
||||
loff_t offset;
|
||||
|
||||
buf.dirent = (void *)__get_free_page(GFP_KERNEL);
|
||||
if (!buf.dirent)
|
||||
return -ENOMEM;
|
||||
|
||||
offset = *offsetp;
|
||||
cdp->err = nfserr_eof; /* will be cleared on successful read */
|
||||
|
||||
while (1) {
|
||||
unsigned int reclen;
|
||||
|
||||
buf.used = 0;
|
||||
buf.full = 0;
|
||||
|
||||
host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf);
|
||||
if (buf.full)
|
||||
host_err = 0;
|
||||
|
||||
if (host_err < 0)
|
||||
break;
|
||||
|
||||
size = buf.used;
|
||||
|
||||
if (!size)
|
||||
break;
|
||||
|
||||
de = (struct buffered_dirent *)buf.dirent;
|
||||
while (size > 0) {
|
||||
offset = de->offset;
|
||||
|
||||
if (func(cdp, de->name, de->namlen, de->offset,
|
||||
de->ino, de->d_type))
|
||||
goto done;
|
||||
|
||||
if (cdp->err != nfs_ok)
|
||||
goto done;
|
||||
|
||||
reclen = ALIGN(sizeof(*de) + de->namlen,
|
||||
sizeof(u64));
|
||||
size -= reclen;
|
||||
de = (struct buffered_dirent *)((char *)de + reclen);
|
||||
}
|
||||
offset = vfs_llseek(file, 0, SEEK_CUR);
|
||||
if (!buf.full)
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
free_page((unsigned long)(buf.dirent));
|
||||
|
||||
if (host_err)
|
||||
return nfserrno(host_err);
|
||||
|
||||
*offsetp = offset;
|
||||
return cdp->err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read entries from a directory.
|
||||
* The NFSv3/4 verifier we ignore for now.
|
||||
@ -1826,7 +1935,6 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
|
||||
struct readdir_cd *cdp, filldir_t func)
|
||||
{
|
||||
__be32 err;
|
||||
int host_err;
|
||||
struct file *file;
|
||||
loff_t offset = *offsetp;
|
||||
|
||||
@ -1840,21 +1948,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the directory entries. This silly loop is necessary because
|
||||
* readdir() is not guaranteed to fill up the entire buffer, but
|
||||
* may choose to do less.
|
||||
*/
|
||||
|
||||
do {
|
||||
cdp->err = nfserr_eof; /* will be cleared on successful read */
|
||||
host_err = vfs_readdir(file, func, cdp);
|
||||
} while (host_err >=0 && cdp->err == nfs_ok);
|
||||
if (host_err)
|
||||
err = nfserrno(host_err);
|
||||
else
|
||||
err = cdp->err;
|
||||
*offsetp = vfs_llseek(file, 0, 1);
|
||||
err = nfsd_buffered_readdir(file, func, cdp, offsetp);
|
||||
|
||||
if (err == nfserr_eof || err == nfserr_toosmall)
|
||||
err = nfs_ok; /* can still be found in ->err */
|
||||
|
@ -304,8 +304,6 @@ static struct dentry *ntfs_get_parent(struct dentry *child_dent)
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ATTR_RECORD *attr;
|
||||
FILE_NAME_ATTR *fn;
|
||||
struct inode *parent_vi;
|
||||
struct dentry *parent_dent;
|
||||
unsigned long parent_ino;
|
||||
int err;
|
||||
|
||||
@ -345,24 +343,8 @@ try_next:
|
||||
/* Release the search context and the mft record of the child. */
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
unmap_mft_record(ni);
|
||||
/* Get the inode of the parent directory. */
|
||||
parent_vi = ntfs_iget(vi->i_sb, parent_ino);
|
||||
if (IS_ERR(parent_vi) || unlikely(is_bad_inode(parent_vi))) {
|
||||
if (!IS_ERR(parent_vi))
|
||||
iput(parent_vi);
|
||||
ntfs_error(vi->i_sb, "Failed to get parent directory inode "
|
||||
"0x%lx of child inode 0x%lx.", parent_ino,
|
||||
vi->i_ino);
|
||||
return ERR_PTR(-EACCES);
|
||||
}
|
||||
/* Finally get a dentry for the parent directory and return it. */
|
||||
parent_dent = d_alloc_anon(parent_vi);
|
||||
if (unlikely(!parent_dent)) {
|
||||
iput(parent_vi);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
ntfs_debug("Done for inode 0x%lx.", vi->i_ino);
|
||||
return parent_dent;
|
||||
|
||||
return d_obtain_alias(ntfs_iget(vi->i_sb, parent_ino));
|
||||
}
|
||||
|
||||
static struct inode *ntfs_nfs_get_inode(struct super_block *sb,
|
||||
|
@ -68,14 +68,9 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb,
|
||||
return ERR_PTR(-ESTALE);
|
||||
}
|
||||
|
||||
result = d_alloc_anon(inode);
|
||||
|
||||
if (!result) {
|
||||
iput(inode);
|
||||
mlog_errno(-ENOMEM);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
result->d_op = &ocfs2_dentry_ops;
|
||||
result = d_obtain_alias(inode);
|
||||
if (!IS_ERR(result))
|
||||
result->d_op = &ocfs2_dentry_ops;
|
||||
|
||||
mlog_exit_ptr(result);
|
||||
return result;
|
||||
@ -86,7 +81,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
|
||||
int status;
|
||||
u64 blkno;
|
||||
struct dentry *parent;
|
||||
struct inode *inode;
|
||||
struct inode *dir = child->d_inode;
|
||||
|
||||
mlog_entry("(0x%p, '%.*s')\n", child,
|
||||
@ -109,21 +103,9 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
|
||||
goto bail_unlock;
|
||||
}
|
||||
|
||||
inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0);
|
||||
if (IS_ERR(inode)) {
|
||||
mlog(ML_ERROR, "Unable to create inode %llu\n",
|
||||
(unsigned long long)blkno);
|
||||
parent = ERR_PTR(-EACCES);
|
||||
goto bail_unlock;
|
||||
}
|
||||
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent) {
|
||||
iput(inode);
|
||||
parent = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
parent->d_op = &ocfs2_dentry_ops;
|
||||
parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
|
||||
if (!IS_ERR(parent))
|
||||
parent->d_op = &ocfs2_dentry_ops;
|
||||
|
||||
bail_unlock:
|
||||
ocfs2_inode_unlock(dir, 0);
|
||||
|
@ -501,4 +501,5 @@ struct inode_operations omfs_dir_inops = {
|
||||
struct file_operations omfs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = omfs_readdir,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
@ -167,6 +167,7 @@ static int openpromfs_readdir(struct file *, void *, filldir_t);
|
||||
static const struct file_operations openprom_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = openpromfs_readdir,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *);
|
||||
|
@ -298,13 +298,19 @@ static int proc_sys_permission(struct inode *inode, int mask)
|
||||
* sysctl entries that are not writeable,
|
||||
* are _NOT_ writeable, capabilities or not.
|
||||
*/
|
||||
struct ctl_table_header *head = grab_header(inode);
|
||||
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
||||
struct ctl_table_header *head;
|
||||
struct ctl_table *table;
|
||||
int error;
|
||||
|
||||
/* Executable files are not allowed under /proc/sys/ */
|
||||
if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))
|
||||
return -EACCES;
|
||||
|
||||
head = grab_header(inode);
|
||||
if (IS_ERR(head))
|
||||
return PTR_ERR(head);
|
||||
|
||||
table = PROC_I(inode)->sysctl_entry;
|
||||
if (!table) /* global root - r-xr-xr-x */
|
||||
error = mask & MAY_WRITE ? -EACCES : 0;
|
||||
else /* Use the permissions on the sysctl table entry */
|
||||
@ -353,6 +359,7 @@ static const struct file_operations proc_sys_file_operations = {
|
||||
|
||||
static const struct file_operations proc_sys_dir_file_operations = {
|
||||
.readdir = proc_sys_readdir,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
static const struct inode_operations proc_sys_inode_operations = {
|
||||
|
@ -31,39 +31,61 @@ const struct file_operations generic_ro_fops = {
|
||||
|
||||
EXPORT_SYMBOL(generic_ro_fops);
|
||||
|
||||
/**
|
||||
* generic_file_llseek_unlocked - lockless generic llseek implementation
|
||||
* @file: file structure to seek on
|
||||
* @offset: file offset to seek to
|
||||
* @origin: type of seek
|
||||
*
|
||||
* Updates the file offset to the value specified by @offset and @origin.
|
||||
* Locking must be provided by the caller.
|
||||
*/
|
||||
loff_t
|
||||
generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
|
||||
{
|
||||
loff_t retval;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
|
||||
switch (origin) {
|
||||
case SEEK_END:
|
||||
offset += inode->i_size;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
offset += file->f_pos;
|
||||
case SEEK_END:
|
||||
offset += inode->i_size;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
offset += file->f_pos;
|
||||
break;
|
||||
}
|
||||
retval = -EINVAL;
|
||||
if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
|
||||
/* Special lock needed here? */
|
||||
if (offset != file->f_pos) {
|
||||
file->f_pos = offset;
|
||||
file->f_version = 0;
|
||||
}
|
||||
retval = offset;
|
||||
|
||||
if (offset < 0 || offset > inode->i_sb->s_maxbytes)
|
||||
return -EINVAL;
|
||||
|
||||
/* Special lock needed here? */
|
||||
if (offset != file->f_pos) {
|
||||
file->f_pos = offset;
|
||||
file->f_version = 0;
|
||||
}
|
||||
return retval;
|
||||
|
||||
return offset;
|
||||
}
|
||||
EXPORT_SYMBOL(generic_file_llseek_unlocked);
|
||||
|
||||
/**
|
||||
* generic_file_llseek - generic llseek implementation for regular files
|
||||
* @file: file structure to seek on
|
||||
* @offset: file offset to seek to
|
||||
* @origin: type of seek
|
||||
*
|
||||
* This is a generic implemenation of ->llseek useable for all normal local
|
||||
* filesystems. It just updates the file offset to the value specified by
|
||||
* @offset and @origin under i_mutex.
|
||||
*/
|
||||
loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
|
||||
{
|
||||
loff_t n;
|
||||
loff_t rval;
|
||||
|
||||
mutex_lock(&file->f_dentry->d_inode->i_mutex);
|
||||
n = generic_file_llseek_unlocked(file, offset, origin);
|
||||
rval = generic_file_llseek_unlocked(file, offset, origin);
|
||||
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
|
||||
return n;
|
||||
|
||||
return rval;
|
||||
}
|
||||
EXPORT_SYMBOL(generic_file_llseek);
|
||||
|
||||
|
22
fs/readdir.c
22
fs/readdir.c
@ -117,7 +117,7 @@ asmlinkage long old_readdir(unsigned int fd, struct old_linux_dirent __user * di
|
||||
buf.dirent = dirent;
|
||||
|
||||
error = vfs_readdir(file, fillonedir, &buf);
|
||||
if (error >= 0)
|
||||
if (buf.result)
|
||||
error = buf.result;
|
||||
|
||||
fput(file);
|
||||
@ -209,9 +209,8 @@ asmlinkage long sys_getdents(unsigned int fd, struct linux_dirent __user * diren
|
||||
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))
|
||||
@ -219,8 +218,6 @@ asmlinkage long sys_getdents(unsigned int fd, struct linux_dirent __user * diren
|
||||
else
|
||||
error = count - buf.count;
|
||||
}
|
||||
|
||||
out_putf:
|
||||
fput(file);
|
||||
out:
|
||||
return error;
|
||||
@ -293,19 +290,16 @@ asmlinkage long sys_getdents64(unsigned int fd, struct linux_dirent64 __user * d
|
||||
buf.error = 0;
|
||||
|
||||
error = vfs_readdir(file, 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(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;
|
||||
|
@ -296,6 +296,7 @@ const struct file_operations reiserfs_file_operations = {
|
||||
.aio_write = generic_file_aio_write,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = generic_file_splice_write,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
const struct inode_operations reiserfs_file_inode_operations = {
|
||||
|
@ -1522,7 +1522,6 @@ static struct dentry *reiserfs_get_dentry(struct super_block *sb,
|
||||
|
||||
{
|
||||
struct cpu_key key;
|
||||
struct dentry *result;
|
||||
struct inode *inode;
|
||||
|
||||
key.on_disk_key.k_objectid = objectid;
|
||||
@ -1535,16 +1534,8 @@ static struct dentry *reiserfs_get_dentry(struct super_block *sb,
|
||||
inode = NULL;
|
||||
}
|
||||
reiserfs_write_unlock(sb);
|
||||
if (!inode)
|
||||
inode = ERR_PTR(-ESTALE);
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
result = d_alloc_anon(inode);
|
||||
if (!result) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return result;
|
||||
|
||||
return d_obtain_alias(inode);
|
||||
}
|
||||
|
||||
struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
|
||||
|
@ -383,7 +383,6 @@ struct dentry *reiserfs_get_parent(struct dentry *child)
|
||||
struct inode *inode = NULL;
|
||||
struct reiserfs_dir_entry de;
|
||||
INITIALIZE_PATH(path_to_entry);
|
||||
struct dentry *parent;
|
||||
struct inode *dir = child->d_inode;
|
||||
|
||||
if (dir->i_nlink == 0) {
|
||||
@ -401,15 +400,7 @@ struct dentry *reiserfs_get_parent(struct dentry *child)
|
||||
inode = reiserfs_iget(dir->i_sb, (struct cpu_key *)&(de.de_dir_id));
|
||||
reiserfs_write_unlock(dir->i_sb);
|
||||
|
||||
if (!inode || IS_ERR(inode)) {
|
||||
return ERR_PTR(-EACCES);
|
||||
}
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent) {
|
||||
iput(inode);
|
||||
parent = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return parent;
|
||||
return d_obtain_alias(inode);
|
||||
}
|
||||
|
||||
/* add entry to the directory (entry can be hidden).
|
||||
|
@ -2058,10 +2058,10 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type)
|
||||
* Standard function to be called on quota_on
|
||||
*/
|
||||
static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
|
||||
char *path, int remount)
|
||||
char *name, int remount)
|
||||
{
|
||||
int err;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
struct inode *inode;
|
||||
struct reiserfs_transaction_handle th;
|
||||
|
||||
@ -2069,16 +2069,16 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
|
||||
return -EINVAL;
|
||||
/* No more checks needed? Path and format_id are bogus anyway... */
|
||||
if (remount)
|
||||
return vfs_quota_on(sb, type, format_id, path, 1);
|
||||
err = path_lookup(path, LOOKUP_FOLLOW, &nd);
|
||||
return vfs_quota_on(sb, type, format_id, name, 1);
|
||||
err = kern_path(name, LOOKUP_FOLLOW, &path);
|
||||
if (err)
|
||||
return err;
|
||||
/* Quotafile not on the same filesystem? */
|
||||
if (nd.path.mnt->mnt_sb != sb) {
|
||||
if (path.mnt->mnt_sb != sb) {
|
||||
err = -EXDEV;
|
||||
goto out;
|
||||
}
|
||||
inode = nd.path.dentry->d_inode;
|
||||
inode = path.dentry->d_inode;
|
||||
/* We must not pack tails for quota files on reiserfs for quota IO to work */
|
||||
if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {
|
||||
err = reiserfs_unpack(inode, NULL);
|
||||
@ -2094,7 +2094,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
|
||||
/* Journaling quota? */
|
||||
if (REISERFS_SB(sb)->s_qf_names[type]) {
|
||||
/* Quotafile not of fs root? */
|
||||
if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode)
|
||||
if (path.dentry->d_parent != sb->s_root)
|
||||
reiserfs_warning(sb,
|
||||
"reiserfs: Quota file not on filesystem root. "
|
||||
"Journalled quota will not work.");
|
||||
@ -2113,9 +2113,9 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
err = vfs_quota_on_path(sb, type, format_id, &nd.path);
|
||||
err = vfs_quota_on_path(sb, type, format_id, &path);
|
||||
out:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
15
fs/super.c
15
fs/super.c
@ -682,7 +682,7 @@ void emergency_remount(void)
|
||||
* filesystems which don't use real block-devices. -- jrs
|
||||
*/
|
||||
|
||||
static struct idr unnamed_dev_idr;
|
||||
static DEFINE_IDA(unnamed_dev_ida);
|
||||
static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */
|
||||
|
||||
int set_anon_super(struct super_block *s, void *data)
|
||||
@ -691,10 +691,10 @@ int set_anon_super(struct super_block *s, void *data)
|
||||
int error;
|
||||
|
||||
retry:
|
||||
if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0)
|
||||
if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)
|
||||
return -ENOMEM;
|
||||
spin_lock(&unnamed_dev_lock);
|
||||
error = idr_get_new(&unnamed_dev_idr, NULL, &dev);
|
||||
error = ida_get_new(&unnamed_dev_ida, &dev);
|
||||
spin_unlock(&unnamed_dev_lock);
|
||||
if (error == -EAGAIN)
|
||||
/* We raced and lost with another CPU. */
|
||||
@ -704,7 +704,7 @@ int set_anon_super(struct super_block *s, void *data)
|
||||
|
||||
if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
|
||||
spin_lock(&unnamed_dev_lock);
|
||||
idr_remove(&unnamed_dev_idr, dev);
|
||||
ida_remove(&unnamed_dev_ida, dev);
|
||||
spin_unlock(&unnamed_dev_lock);
|
||||
return -EMFILE;
|
||||
}
|
||||
@ -720,17 +720,12 @@ void kill_anon_super(struct super_block *sb)
|
||||
|
||||
generic_shutdown_super(sb);
|
||||
spin_lock(&unnamed_dev_lock);
|
||||
idr_remove(&unnamed_dev_idr, slot);
|
||||
ida_remove(&unnamed_dev_ida, slot);
|
||||
spin_unlock(&unnamed_dev_lock);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(kill_anon_super);
|
||||
|
||||
void __init unnamed_dev_init(void)
|
||||
{
|
||||
idr_init(&unnamed_dev_idr);
|
||||
}
|
||||
|
||||
void kill_litter_super(struct super_block *sb)
|
||||
{
|
||||
if (sb->s_root)
|
||||
|
@ -983,4 +983,5 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
||||
const struct file_operations sysfs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = sysfs_readdir,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
@ -142,7 +142,7 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
|
||||
}
|
||||
|
||||
static struct fileIdentDesc *udf_find_entry(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
struct qstr *child,
|
||||
struct udf_fileident_bh *fibh,
|
||||
struct fileIdentDesc *cfi)
|
||||
{
|
||||
@ -159,8 +159,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
|
||||
sector_t offset;
|
||||
struct extent_position epos = {};
|
||||
struct udf_inode_info *dinfo = UDF_I(dir);
|
||||
int isdotdot = dentry->d_name.len == 2 &&
|
||||
dentry->d_name.name[0] == '.' && dentry->d_name.name[1] == '.';
|
||||
int isdotdot = child->len == 2 &&
|
||||
child->name[0] == '.' && child->name[1] == '.';
|
||||
|
||||
size = udf_ext0_offset(dir) + dir->i_size;
|
||||
f_pos = udf_ext0_offset(dir);
|
||||
@ -238,8 +238,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
|
||||
continue;
|
||||
|
||||
flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
|
||||
if (flen && udf_match(flen, fname, dentry->d_name.len,
|
||||
dentry->d_name.name))
|
||||
if (flen && udf_match(flen, fname, child->len, child->name))
|
||||
goto out_ok;
|
||||
}
|
||||
|
||||
@ -283,7 +282,7 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
|
||||
} else
|
||||
#endif /* UDF_RECOVERY */
|
||||
|
||||
if (udf_find_entry(dir, dentry, &fibh, &cfi)) {
|
||||
if (udf_find_entry(dir, &dentry->d_name, &fibh, &cfi)) {
|
||||
if (fibh.sbh != fibh.ebh)
|
||||
brelse(fibh.ebh);
|
||||
brelse(fibh.sbh);
|
||||
@ -783,7 +782,7 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
|
||||
retval = -ENOENT;
|
||||
lock_kernel();
|
||||
fi = udf_find_entry(dir, dentry, &fibh, &cfi);
|
||||
fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
|
||||
if (!fi)
|
||||
goto out;
|
||||
|
||||
@ -829,7 +828,7 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)
|
||||
|
||||
retval = -ENOENT;
|
||||
lock_kernel();
|
||||
fi = udf_find_entry(dir, dentry, &fibh, &cfi);
|
||||
fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
|
||||
if (!fi)
|
||||
goto out;
|
||||
|
||||
@ -1113,7 +1112,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct udf_inode_info *old_iinfo = UDF_I(old_inode);
|
||||
|
||||
lock_kernel();
|
||||
ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
|
||||
ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
|
||||
if (ofi) {
|
||||
if (ofibh.sbh != ofibh.ebh)
|
||||
brelse(ofibh.ebh);
|
||||
@ -1124,7 +1123,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
!= old_inode->i_ino)
|
||||
goto end_rename;
|
||||
|
||||
nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
|
||||
nfi = udf_find_entry(new_dir, &new_dentry->d_name, &nfibh, &ncfi);
|
||||
if (nfi) {
|
||||
if (!new_inode) {
|
||||
if (nfibh.sbh != nfibh.ebh)
|
||||
@ -1192,7 +1191,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);
|
||||
|
||||
/* The old fid may have moved - find it again */
|
||||
ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
|
||||
ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
|
||||
udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
|
||||
|
||||
if (new_inode) {
|
||||
@ -1243,15 +1242,11 @@ end_rename:
|
||||
|
||||
static struct dentry *udf_get_parent(struct dentry *child)
|
||||
{
|
||||
struct dentry *parent;
|
||||
struct inode *inode = NULL;
|
||||
struct dentry dotdot;
|
||||
struct qstr dotdot = {.name = "..", .len = 2};
|
||||
struct fileIdentDesc cfi;
|
||||
struct udf_fileident_bh fibh;
|
||||
|
||||
dotdot.d_name.name = "..";
|
||||
dotdot.d_name.len = 2;
|
||||
|
||||
lock_kernel();
|
||||
if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi))
|
||||
goto out_unlock;
|
||||
@ -1266,13 +1261,7 @@ static struct dentry *udf_get_parent(struct dentry *child)
|
||||
goto out_unlock;
|
||||
unlock_kernel();
|
||||
|
||||
parent = d_alloc_anon(inode);
|
||||
if (!parent) {
|
||||
iput(inode);
|
||||
parent = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return parent;
|
||||
return d_obtain_alias(inode);
|
||||
out_unlock:
|
||||
unlock_kernel();
|
||||
return ERR_PTR(-EACCES);
|
||||
@ -1283,7 +1272,6 @@ static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
|
||||
u16 partref, __u32 generation)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dentry *result;
|
||||
kernel_lb_addr loc;
|
||||
|
||||
if (block == 0)
|
||||
@ -1300,12 +1288,7 @@ static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
|
||||
iput(inode);
|
||||
return ERR_PTR(-ESTALE);
|
||||
}
|
||||
result = d_alloc_anon(inode);
|
||||
if (!result) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return result;
|
||||
return d_obtain_alias(inode);
|
||||
}
|
||||
|
||||
static struct dentry *udf_fh_to_dentry(struct super_block *sb,
|
||||
|
@ -667,4 +667,5 @@ const struct file_operations ufs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = ufs_readdir,
|
||||
.fsync = file_fsync,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
@ -148,7 +148,6 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
|
||||
{
|
||||
struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;
|
||||
struct inode *inode = NULL;
|
||||
struct dentry *result;
|
||||
|
||||
if (fh_len < xfs_fileid_length(fileid_type))
|
||||
return NULL;
|
||||
@ -164,16 +163,7 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
result = d_alloc_anon(inode);
|
||||
if (!result) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return result;
|
||||
return d_obtain_alias(inode);
|
||||
}
|
||||
|
||||
STATIC struct dentry *
|
||||
@ -182,7 +172,6 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
|
||||
{
|
||||
struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;
|
||||
struct inode *inode = NULL;
|
||||
struct dentry *result;
|
||||
|
||||
switch (fileid_type) {
|
||||
case FILEID_INO32_GEN_PARENT:
|
||||
@ -195,16 +184,7 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
result = d_alloc_anon(inode);
|
||||
if (!result) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return result;
|
||||
return d_obtain_alias(inode);
|
||||
}
|
||||
|
||||
STATIC struct dentry *
|
||||
@ -213,18 +193,12 @@ xfs_fs_get_parent(
|
||||
{
|
||||
int error;
|
||||
struct xfs_inode *cip;
|
||||
struct dentry *parent;
|
||||
|
||||
error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL);
|
||||
if (unlikely(error))
|
||||
return ERR_PTR(-error);
|
||||
|
||||
parent = d_alloc_anon(VFS_I(cip));
|
||||
if (unlikely(!parent)) {
|
||||
iput(VFS_I(cip));
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
return parent;
|
||||
return d_obtain_alias(VFS_I(cip));
|
||||
}
|
||||
|
||||
const struct export_operations xfs_export_operations = {
|
||||
|
@ -204,15 +204,6 @@ xfs_file_fsync(
|
||||
return -xfs_fsync(XFS_I(dentry->d_inode));
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately we can't just use the clean and simple readdir implementation
|
||||
* below, because nfs might call back into ->lookup from the filldir callback
|
||||
* and that will deadlock the low-level btree code.
|
||||
*
|
||||
* Hopefully we'll find a better workaround that allows to use the optimal
|
||||
* version at least for local readdirs for 2.6.25.
|
||||
*/
|
||||
#if 0
|
||||
STATIC int
|
||||
xfs_file_readdir(
|
||||
struct file *filp,
|
||||
@ -244,125 +235,6 @@ xfs_file_readdir(
|
||||
return -error;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
struct hack_dirent {
|
||||
u64 ino;
|
||||
loff_t offset;
|
||||
int namlen;
|
||||
unsigned int d_type;
|
||||
char name[];
|
||||
};
|
||||
|
||||
struct hack_callback {
|
||||
char *dirent;
|
||||
size_t len;
|
||||
size_t used;
|
||||
};
|
||||
|
||||
STATIC int
|
||||
xfs_hack_filldir(
|
||||
void *__buf,
|
||||
const char *name,
|
||||
int namlen,
|
||||
loff_t offset,
|
||||
u64 ino,
|
||||
unsigned int d_type)
|
||||
{
|
||||
struct hack_callback *buf = __buf;
|
||||
struct hack_dirent *de = (struct hack_dirent *)(buf->dirent + buf->used);
|
||||
unsigned int reclen;
|
||||
|
||||
reclen = ALIGN(sizeof(struct hack_dirent) + namlen, sizeof(u64));
|
||||
if (buf->used + reclen > buf->len)
|
||||
return -EINVAL;
|
||||
|
||||
de->namlen = namlen;
|
||||
de->offset = offset;
|
||||
de->ino = ino;
|
||||
de->d_type = d_type;
|
||||
memcpy(de->name, name, namlen);
|
||||
buf->used += reclen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_file_readdir(
|
||||
struct file *filp,
|
||||
void *dirent,
|
||||
filldir_t filldir)
|
||||
{
|
||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||
xfs_inode_t *ip = XFS_I(inode);
|
||||
struct hack_callback buf;
|
||||
struct hack_dirent *de;
|
||||
int error;
|
||||
loff_t size;
|
||||
int eof = 0;
|
||||
xfs_off_t start_offset, curr_offset, offset;
|
||||
|
||||
/*
|
||||
* Try fairly hard to get memory
|
||||
*/
|
||||
buf.len = PAGE_CACHE_SIZE;
|
||||
do {
|
||||
buf.dirent = kmalloc(buf.len, GFP_KERNEL);
|
||||
if (buf.dirent)
|
||||
break;
|
||||
buf.len >>= 1;
|
||||
} while (buf.len >= 1024);
|
||||
|
||||
if (!buf.dirent)
|
||||
return -ENOMEM;
|
||||
|
||||
curr_offset = filp->f_pos;
|
||||
if (curr_offset == 0x7fffffff)
|
||||
offset = 0xffffffff;
|
||||
else
|
||||
offset = filp->f_pos;
|
||||
|
||||
while (!eof) {
|
||||
unsigned int reclen;
|
||||
|
||||
start_offset = offset;
|
||||
|
||||
buf.used = 0;
|
||||
error = -xfs_readdir(ip, &buf, buf.len, &offset,
|
||||
xfs_hack_filldir);
|
||||
if (error || offset == start_offset) {
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
size = buf.used;
|
||||
de = (struct hack_dirent *)buf.dirent;
|
||||
while (size > 0) {
|
||||
curr_offset = de->offset /* & 0x7fffffff */;
|
||||
if (filldir(dirent, de->name, de->namlen,
|
||||
curr_offset & 0x7fffffff,
|
||||
de->ino, de->d_type)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
reclen = ALIGN(sizeof(struct hack_dirent) + de->namlen,
|
||||
sizeof(u64));
|
||||
size -= reclen;
|
||||
de = (struct hack_dirent *)((char *)de + reclen);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (!error) {
|
||||
if (size == 0)
|
||||
filp->f_pos = offset & 0x7fffffff;
|
||||
else if (de)
|
||||
filp->f_pos = curr_offset;
|
||||
}
|
||||
|
||||
kfree(buf.dirent);
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC int
|
||||
xfs_file_mmap(
|
||||
|
@ -311,11 +311,10 @@ xfs_open_by_handle(
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
dentry = d_alloc_anon(inode);
|
||||
if (dentry == NULL) {
|
||||
iput(inode);
|
||||
dentry = d_obtain_alias(inode);
|
||||
if (IS_ERR(dentry)) {
|
||||
put_unused_fd(new_fd);
|
||||
return -XFS_ERROR(ENOMEM);
|
||||
return PTR_ERR(dentry);
|
||||
}
|
||||
|
||||
/* Ensure umount returns EBUSY on umounts while this file is open. */
|
||||
|
@ -228,9 +228,9 @@ extern void d_delete(struct dentry *);
|
||||
|
||||
/* allocate/de-allocate */
|
||||
extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
|
||||
extern struct dentry * d_alloc_anon(struct inode *);
|
||||
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
|
||||
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
|
||||
extern struct dentry * d_obtain_alias(struct inode *);
|
||||
extern void shrink_dcache_sb(struct super_block *);
|
||||
extern void shrink_dcache_parent(struct dentry *);
|
||||
extern void shrink_dcache_for_umount(struct super_block *);
|
||||
@ -287,6 +287,7 @@ static inline struct dentry *d_add_unique(struct dentry *entry, struct inode *in
|
||||
|
||||
/* used for rename() and baskets */
|
||||
extern void d_move(struct dentry *, struct dentry *);
|
||||
extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
|
||||
|
||||
/* appendix may either be NULL or be used for transname suffixes */
|
||||
extern struct dentry * d_lookup(struct dentry *, struct qstr *);
|
||||
|
@ -136,7 +136,7 @@ extern int dir_notify_enable;
|
||||
/*
|
||||
* Superblock flags that can be altered by MS_REMOUNT
|
||||
*/
|
||||
#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK)
|
||||
#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION)
|
||||
|
||||
/*
|
||||
* Old magic mount flag and mask
|
||||
@ -1593,7 +1593,6 @@ extern int get_sb_pseudo(struct file_system_type *, char *,
|
||||
struct vfsmount *mnt);
|
||||
extern int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
|
||||
int __put_super_and_need_restart(struct super_block *sb);
|
||||
void unnamed_dev_init(void);
|
||||
|
||||
/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
|
||||
#define fops_get(fops) \
|
||||
@ -1852,6 +1851,11 @@ extern int inode_permission(struct inode *, int);
|
||||
extern int generic_permission(struct inode *, int,
|
||||
int (*check_acl)(struct inode *, int));
|
||||
|
||||
static inline bool execute_ok(struct inode *inode)
|
||||
{
|
||||
return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode);
|
||||
}
|
||||
|
||||
extern int get_write_access(struct inode *);
|
||||
extern int deny_write_access(struct file *);
|
||||
static inline void put_write_access(struct inode * inode)
|
||||
|
@ -51,8 +51,10 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
||||
/*
|
||||
* Intent data
|
||||
*/
|
||||
#define LOOKUP_OPEN (0x0100)
|
||||
#define LOOKUP_CREATE (0x0200)
|
||||
#define LOOKUP_OPEN 0x0100
|
||||
#define LOOKUP_CREATE 0x0200
|
||||
#define LOOKUP_EXCL 0x0400
|
||||
#define LOOKUP_RENAME_TARGET 0x0800
|
||||
|
||||
extern int user_path_at(int, const char __user *, unsigned, struct path *);
|
||||
|
||||
@ -61,6 +63,8 @@ extern int user_path_at(int, const char __user *, unsigned, struct path *);
|
||||
#define user_path_dir(name, path) \
|
||||
user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path)
|
||||
|
||||
extern int kern_path(const char *, unsigned, struct path *);
|
||||
|
||||
extern int path_lookup(const char *, unsigned, struct nameidata *);
|
||||
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
|
||||
const char *, unsigned int, struct nameidata *);
|
||||
|
@ -672,7 +672,6 @@ asmlinkage void __init start_kernel(void)
|
||||
fork_init(num_physpages);
|
||||
proc_caches_init();
|
||||
buffer_init();
|
||||
unnamed_dev_init();
|
||||
key_init();
|
||||
security_init();
|
||||
vfs_caches_init(num_physpages);
|
||||
|
@ -532,7 +532,7 @@ void audit_trim_trees(void)
|
||||
list_add(&cursor, &tree_list);
|
||||
while (cursor.next != &tree_list) {
|
||||
struct audit_tree *tree;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
struct vfsmount *root_mnt;
|
||||
struct node *node;
|
||||
struct list_head list;
|
||||
@ -544,12 +544,12 @@ void audit_trim_trees(void)
|
||||
list_add(&cursor, &tree->list);
|
||||
mutex_unlock(&audit_filter_mutex);
|
||||
|
||||
err = path_lookup(tree->pathname, 0, &nd);
|
||||
err = kern_path(tree->pathname, 0, &path);
|
||||
if (err)
|
||||
goto skip_it;
|
||||
|
||||
root_mnt = collect_mounts(nd.path.mnt, nd.path.dentry);
|
||||
path_put(&nd.path);
|
||||
root_mnt = collect_mounts(path.mnt, path.dentry);
|
||||
path_put(&path);
|
||||
if (!root_mnt)
|
||||
goto skip_it;
|
||||
|
||||
@ -580,19 +580,19 @@ skip_it:
|
||||
}
|
||||
|
||||
static int is_under(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
struct path *path)
|
||||
{
|
||||
if (mnt != nd->path.mnt) {
|
||||
if (mnt != path->mnt) {
|
||||
for (;;) {
|
||||
if (mnt->mnt_parent == mnt)
|
||||
return 0;
|
||||
if (mnt->mnt_parent == nd->path.mnt)
|
||||
if (mnt->mnt_parent == path->mnt)
|
||||
break;
|
||||
mnt = mnt->mnt_parent;
|
||||
}
|
||||
dentry = mnt->mnt_mountpoint;
|
||||
}
|
||||
return is_subdir(dentry, nd->path.dentry);
|
||||
return is_subdir(dentry, path->dentry);
|
||||
}
|
||||
|
||||
int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
|
||||
@ -618,7 +618,7 @@ void audit_put_tree(struct audit_tree *tree)
|
||||
int audit_add_tree_rule(struct audit_krule *rule)
|
||||
{
|
||||
struct audit_tree *seed = rule->tree, *tree;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
struct vfsmount *mnt, *p;
|
||||
struct list_head list;
|
||||
int err;
|
||||
@ -637,11 +637,11 @@ int audit_add_tree_rule(struct audit_krule *rule)
|
||||
/* do not set rule->tree yet */
|
||||
mutex_unlock(&audit_filter_mutex);
|
||||
|
||||
err = path_lookup(tree->pathname, 0, &nd);
|
||||
err = kern_path(tree->pathname, 0, &path);
|
||||
if (err)
|
||||
goto Err;
|
||||
mnt = collect_mounts(nd.path.mnt, nd.path.dentry);
|
||||
path_put(&nd.path);
|
||||
mnt = collect_mounts(path.mnt, path.dentry);
|
||||
path_put(&path);
|
||||
if (!mnt) {
|
||||
err = -ENOMEM;
|
||||
goto Err;
|
||||
@ -690,29 +690,29 @@ int audit_tag_tree(char *old, char *new)
|
||||
{
|
||||
struct list_head cursor, barrier;
|
||||
int failed = 0;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
struct vfsmount *tagged;
|
||||
struct list_head list;
|
||||
struct vfsmount *mnt;
|
||||
struct dentry *dentry;
|
||||
int err;
|
||||
|
||||
err = path_lookup(new, 0, &nd);
|
||||
err = kern_path(new, 0, &path);
|
||||
if (err)
|
||||
return err;
|
||||
tagged = collect_mounts(nd.path.mnt, nd.path.dentry);
|
||||
path_put(&nd.path);
|
||||
tagged = collect_mounts(path.mnt, path.dentry);
|
||||
path_put(&path);
|
||||
if (!tagged)
|
||||
return -ENOMEM;
|
||||
|
||||
err = path_lookup(old, 0, &nd);
|
||||
err = kern_path(old, 0, &path);
|
||||
if (err) {
|
||||
drop_collected_mounts(tagged);
|
||||
return err;
|
||||
}
|
||||
mnt = mntget(nd.path.mnt);
|
||||
dentry = dget(nd.path.dentry);
|
||||
path_put(&nd.path);
|
||||
mnt = mntget(path.mnt);
|
||||
dentry = dget(path.dentry);
|
||||
path_put(&path);
|
||||
|
||||
if (dentry == tagged->mnt_root && dentry == mnt->mnt_root)
|
||||
follow_up(&mnt, &dentry);
|
||||
@ -733,7 +733,7 @@ int audit_tag_tree(char *old, char *new)
|
||||
list_add(&cursor, &tree->list);
|
||||
mutex_unlock(&audit_filter_mutex);
|
||||
|
||||
err = path_lookup(tree->pathname, 0, &nd);
|
||||
err = kern_path(tree->pathname, 0, &path);
|
||||
if (err) {
|
||||
put_tree(tree);
|
||||
mutex_lock(&audit_filter_mutex);
|
||||
@ -741,15 +741,15 @@ int audit_tag_tree(char *old, char *new)
|
||||
}
|
||||
|
||||
spin_lock(&vfsmount_lock);
|
||||
if (!is_under(mnt, dentry, &nd)) {
|
||||
if (!is_under(mnt, dentry, &path)) {
|
||||
spin_unlock(&vfsmount_lock);
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
put_tree(tree);
|
||||
mutex_lock(&audit_filter_mutex);
|
||||
continue;
|
||||
}
|
||||
spin_unlock(&vfsmount_lock);
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
|
||||
list_for_each_entry(p, &list, mnt_list) {
|
||||
failed = tag_chunk(p->mnt_root->d_inode, tree);
|
||||
|
@ -711,28 +711,30 @@ static struct sock *unix_find_other(struct net *net,
|
||||
int type, unsigned hash, int *error)
|
||||
{
|
||||
struct sock *u;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int err = 0;
|
||||
|
||||
if (sunname->sun_path[0]) {
|
||||
err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd);
|
||||
struct inode *inode;
|
||||
err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path);
|
||||
if (err)
|
||||
goto fail;
|
||||
err = vfs_permission(&nd, MAY_WRITE);
|
||||
inode = path.dentry->d_inode;
|
||||
err = inode_permission(inode, MAY_WRITE);
|
||||
if (err)
|
||||
goto put_fail;
|
||||
|
||||
err = -ECONNREFUSED;
|
||||
if (!S_ISSOCK(nd.path.dentry->d_inode->i_mode))
|
||||
if (!S_ISSOCK(inode->i_mode))
|
||||
goto put_fail;
|
||||
u = unix_find_socket_byinode(net, nd.path.dentry->d_inode);
|
||||
u = unix_find_socket_byinode(net, inode);
|
||||
if (!u)
|
||||
goto put_fail;
|
||||
|
||||
if (u->sk_type == type)
|
||||
touch_atime(nd.path.mnt, nd.path.dentry);
|
||||
touch_atime(path.mnt, path.dentry);
|
||||
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
|
||||
err=-EPROTOTYPE;
|
||||
if (u->sk_type != type) {
|
||||
@ -753,7 +755,7 @@ static struct sock *unix_find_other(struct net *net,
|
||||
return u;
|
||||
|
||||
put_fail:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
fail:
|
||||
*error=err;
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user