1
0
Fork 0

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.
  ...
hifive-unleashed-5.1
Linus Torvalds 2008-10-23 10:22:40 -07:00
commit 5ed487bc2c
76 changed files with 890 additions and 1140 deletions

View File

@ -165,14 +165,11 @@ osf_getdirentries(unsigned int fd, struct osf_dirent __user *dirent,
buf.error = 0; buf.error = 0;
error = vfs_readdir(file, osf_filldir, &buf); error = vfs_readdir(file, osf_filldir, &buf);
if (error < 0) if (error >= 0)
goto out_putf; error = buf.error;
error = buf.error;
if (count != buf.count) if (count != buf.count)
error = count - buf.count; error = count - buf.count;
out_putf:
fput(file); fput(file);
out: out:
return error; return error;

View File

@ -127,9 +127,8 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
buf.error = 0; buf.error = 0;
error = vfs_readdir(file, filldir, &buf); error = vfs_readdir(file, filldir, &buf);
if (error < 0) if (error >= 0)
goto out_putf; error = buf.error;
error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;
if (lastdirent) { if (lastdirent) {
if (put_user(file->f_pos, &lastdirent->d_off)) if (put_user(file->f_pos, &lastdirent->d_off))

View File

@ -69,9 +69,9 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
if (!IS_ERR(tmp)) { if (!IS_ERR(tmp)) {
struct nameidata nd; struct nameidata nd;
ret = path_lookup(tmp, LOOKUP_PARENT| ret = path_lookup(tmp, LOOKUP_PARENT, &nd);
LOOKUP_OPEN|LOOKUP_CREATE, &nd);
if (!ret) { if (!ret) {
nd.flags |= LOOKUP_OPEN | LOOKUP_CREATE;
ret = spufs_create(&nd, flags, mode, neighbor); ret = spufs_create(&nd, flags, mode, neighbor);
path_put(&nd.path); path_put(&nd.path);
} }

View File

@ -312,19 +312,6 @@ static inline int check_space(struct dm_table *t)
return 0; 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. * 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; return -EOVERFLOW;
} else { } else {
/* convert the path to a device */ /* convert the path to a device */
if ((r = lookup_device(path, &dev))) struct block_device *bdev = lookup_bdev(path);
return r;
if (IS_ERR(bdev))
return PTR_ERR(bdev);
dev = bdev->bd_dev;
bdput(bdev);
} }
dd = find_device(&t->devices, dev); dd = find_device(&t->devices, dev);

View File

@ -22,9 +22,10 @@ source "fs/jbd2/Kconfig"
config FS_MBCACHE config FS_MBCACHE
# Meta block cache for Extended Attributes (ext2/ext3/ext4) # Meta block cache for Extended Attributes (ext2/ext3/ext4)
tristate tristate
depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR default y if EXT2_FS=y && EXT2_FS_XATTR
default y if EXT2_FS=y || EXT3_FS=y || EXT4_FS=y default y if EXT3_FS=y && EXT3_FS_XATTR
default m if EXT2_FS=m || EXT3_FS=m || EXT4_FS=m default y if EXT4_FS=y && EXT4_FS_XATTR
default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR
config REISERFS_FS config REISERFS_FS
tristate "Reiserfs support" tristate "Reiserfs support"

View File

@ -45,6 +45,7 @@ const struct file_operations afs_dir_file_operations = {
.release = afs_release, .release = afs_release,
.readdir = afs_readdir, .readdir = afs_readdir,
.lock = afs_lock, .lock = afs_lock,
.llseek = generic_file_llseek,
}; };
const struct inode_operations afs_dir_inode_operations = { const struct inode_operations afs_dir_inode_operations = {

View File

@ -159,17 +159,17 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
return 0; return 0;
error = security_inode_setattr(dentry, attr);
if (error)
return error;
if (ia_valid & ATTR_SIZE) if (ia_valid & ATTR_SIZE)
down_write(&dentry->d_inode->i_alloc_sem); down_write(&dentry->d_inode->i_alloc_sem);
if (inode->i_op && inode->i_op->setattr) { if (inode->i_op && inode->i_op->setattr) {
error = security_inode_setattr(dentry, attr); error = inode->i_op->setattr(dentry, attr);
if (!error)
error = inode->i_op->setattr(dentry, attr);
} else { } else {
error = inode_change_ok(inode, attr); error = inode_change_ok(inode, attr);
if (!error)
error = security_inode_setattr(dentry, attr);
if (!error) { if (!error) {
if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))

View File

@ -80,6 +80,7 @@ const struct file_operations bfs_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = bfs_readdir, .readdir = bfs_readdir,
.fsync = file_fsync, .fsync = file_fsync,
.llseek = generic_file_llseek,
}; };
extern void dump_imap(const char *, struct super_block *); extern void dump_imap(const char *, struct super_block *);

View File

@ -1268,33 +1268,33 @@ EXPORT_SYMBOL(ioctl_by_bdev);
* namespace if possible and return it. Return ERR_PTR(error) * namespace if possible and return it. Return ERR_PTR(error)
* otherwise. * otherwise.
*/ */
struct block_device *lookup_bdev(const char *path) struct block_device *lookup_bdev(const char *pathname)
{ {
struct block_device *bdev; struct block_device *bdev;
struct inode *inode; struct inode *inode;
struct nameidata nd; struct path path;
int error; int error;
if (!path || !*path) if (!pathname || !*pathname)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
error = path_lookup(path, LOOKUP_FOLLOW, &nd); error = kern_path(pathname, LOOKUP_FOLLOW, &path);
if (error) if (error)
return ERR_PTR(error); return ERR_PTR(error);
inode = nd.path.dentry->d_inode; inode = path.dentry->d_inode;
error = -ENOTBLK; error = -ENOTBLK;
if (!S_ISBLK(inode->i_mode)) if (!S_ISBLK(inode->i_mode))
goto fail; goto fail;
error = -EACCES; error = -EACCES;
if (nd.path.mnt->mnt_flags & MNT_NODEV) if (path.mnt->mnt_flags & MNT_NODEV)
goto fail; goto fail;
error = -ENOMEM; error = -ENOMEM;
bdev = bd_acquire(inode); bdev = bd_acquire(inode);
if (!bdev) if (!bdev)
goto fail; goto fail;
out: out:
path_put(&nd.path); path_put(&path);
return bdev; return bdev;
fail: fail:
bdev = ERR_PTR(error); bdev = ERR_PTR(error);

View File

@ -386,15 +386,22 @@ static int chrdev_open(struct inode *inode, struct file *filp)
cdev_put(new); cdev_put(new);
if (ret) if (ret)
return ret; return ret;
ret = -ENXIO;
filp->f_op = fops_get(p->ops); filp->f_op = fops_get(p->ops);
if (!filp->f_op) { if (!filp->f_op)
cdev_put(p); goto out_cdev_put;
return -ENXIO;
} if (filp->f_op->open) {
if (filp->f_op->open)
ret = filp->f_op->open(inode,filp); ret = filp->f_op->open(inode,filp);
if (ret) if (ret)
cdev_put(p); goto out_cdev_put;
}
return 0;
out_cdev_put:
cdev_put(p);
return ret; return ret;
} }

View File

@ -275,9 +275,12 @@ static int cifs_permission(struct inode *inode, int mask)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
return 0; if ((mask & MAY_EXEC) && !execute_ok(inode))
else /* file mode might have been restricted at mount time 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 on the client (above and beyond ACL on servers) for
servers which do not support setting and viewing mode bits, servers which do not support setting and viewing mode bits,
so allowing client to check permissions is useful */ so allowing client to check permissions is useful */
@ -765,6 +768,7 @@ const struct file_operations cifs_dir_ops = {
.dir_notify = cifs_dir_notify, .dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */ #endif /* CONFIG_CIFS_EXPERIMENTAL */
.unlocked_ioctl = cifs_ioctl, .unlocked_ioctl = cifs_ioctl,
.llseek = generic_file_llseek,
}; };
static void static void

View File

@ -146,6 +146,9 @@ int coda_permission(struct inode *inode, int mask)
if (!mask) if (!mask)
return 0; return 0;
if ((mask & MAY_EXEC) && !execute_ok(inode))
return -EACCES;
lock_kernel(); lock_kernel();
if (coda_cache_check(inode, mask)) if (coda_cache_check(inode, mask))

View File

@ -43,7 +43,7 @@ const struct file_operations coda_ioctl_operations = {
/* the coda pioctl inode ops */ /* the coda pioctl inode ops */
static int coda_ioctl_permission(struct inode *inode, int mask) 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, static int coda_pioctl(struct inode * inode, struct file * filp,

View File

@ -869,7 +869,7 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
buf.dirent = dirent; buf.dirent = dirent;
error = vfs_readdir(file, compat_fillonedir, &buf); error = vfs_readdir(file, compat_fillonedir, &buf);
if (error >= 0) if (buf.result)
error = buf.result; error = buf.result;
fput(file); fput(file);
@ -956,9 +956,8 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
buf.error = 0; buf.error = 0;
error = vfs_readdir(file, compat_filldir, &buf); error = vfs_readdir(file, compat_filldir, &buf);
if (error < 0) if (error >= 0)
goto out_putf; error = buf.error;
error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;
if (lastdirent) { if (lastdirent) {
if (put_user(file->f_pos, &lastdirent->d_off)) if (put_user(file->f_pos, &lastdirent->d_off))
@ -966,8 +965,6 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
else else
error = count - buf.count; error = count - buf.count;
} }
out_putf:
fput(file); fput(file);
out: out:
return error; return error;
@ -1047,19 +1044,16 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
buf.error = 0; buf.error = 0;
error = vfs_readdir(file, compat_filldir64, &buf); error = vfs_readdir(file, compat_filldir64, &buf);
if (error < 0) if (error >= 0)
goto out_putf; error = buf.error;
error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;
if (lastdirent) { if (lastdirent) {
typeof(lastdirent->d_off) d_off = file->f_pos; typeof(lastdirent->d_off) d_off = file->f_pos;
error = -EFAULT;
if (__put_user_unaligned(d_off, &lastdirent->d_off)) if (__put_user_unaligned(d_off, &lastdirent->d_off))
goto out_putf; error = -EFAULT;
error = count - buf.count; else
error = count - buf.count;
} }
out_putf:
fput(file); fput(file);
out: out:
return error; return error;

View File

@ -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) struct config_item **target)
{ {
int ret; int ret;
ret = path_lookup(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, nd); ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
if (!ret) { if (!ret) {
if (nd->path.dentry->d_sb == configfs_sb) { if (path->dentry->d_sb == configfs_sb) {
*target = configfs_get_config_item(nd->path.dentry); *target = configfs_get_config_item(path->dentry);
if (!*target) { if (!*target) {
ret = -ENOENT; ret = -ENOENT;
path_put(&nd->path); path_put(path);
} }
} else } else
ret = -EPERM; 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 configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{ {
int ret; int ret;
struct nameidata nd; struct path path;
struct configfs_dirent *sd; struct configfs_dirent *sd;
struct config_item *parent_item; struct config_item *parent_item;
struct config_item *target_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) !type->ct_item_ops->allow_link)
goto out_put; goto out_put;
ret = get_target(symname, &nd, &target_item); ret = get_target(symname, &path, &target_item);
if (ret) if (ret)
goto out_put; goto out_put;
@ -174,7 +174,7 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna
} }
config_item_put(target_item); config_item_put(target_item);
path_put(&nd.path); path_put(&path);
out_put: out_put:
config_item_put(parent_item); config_item_put(parent_item);

View File

@ -69,6 +69,7 @@ struct dentry_stat_t dentry_stat = {
static void __d_free(struct dentry *dentry) static void __d_free(struct dentry *dentry)
{ {
WARN_ON(!list_empty(&dentry->d_alias));
if (dname_external(dentry)) if (dname_external(dentry))
kfree(dentry->d_name.name); kfree(dentry->d_name.name);
kmem_cache_free(dentry_cache, dentry); 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 */ dentry_stat.nr_dentry--; /* For d_free, below */
/*drops the locks, at that point nobody can reach this dentry */ /*drops the locks, at that point nobody can reach this dentry */
dentry_iput(dentry); dentry_iput(dentry);
parent = dentry->d_parent; if (IS_ROOT(dentry))
parent = NULL;
else
parent = dentry->d_parent;
d_free(dentry); 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(); BUG();
} }
parent = dentry->d_parent; if (IS_ROOT(dentry))
if (parent == dentry)
parent = NULL; parent = NULL;
else else {
parent = dentry->d_parent;
atomic_dec(&parent->d_count); atomic_dec(&parent->d_count);
}
list_del(&dentry->d_u.d_child); list_del(&dentry->d_u.d_child);
detached++; detached++;
@ -977,6 +982,15 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
return d_alloc(parent, &q); 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 * d_instantiate - fill in inode information for a dentry
* @entry: dentry to complete * @entry: dentry to complete
@ -996,10 +1010,7 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
{ {
BUG_ON(!list_empty(&entry->d_alias)); BUG_ON(!list_empty(&entry->d_alias));
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
if (inode) __d_instantiate(entry, inode);
list_add(&entry->d_alias, &inode->i_dentry);
entry->d_inode = inode;
fsnotify_d_instantiate(entry, inode);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
security_d_instantiate(entry, inode); 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; unsigned int hash = entry->d_name.hash;
if (!inode) { if (!inode) {
entry->d_inode = NULL; __d_instantiate(entry, NULL);
return NULL; return NULL;
} }
@ -1048,9 +1059,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
return alias; return alias;
} }
list_add(&entry->d_alias, &inode->i_dentry); __d_instantiate(entry, inode);
entry->d_inode = inode;
fsnotify_d_instantiate(entry, inode);
return NULL; 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 * @inode: inode to allocate the dentry for
* *
* This is similar to d_alloc_root. It is used by filesystems when * Obtain a dentry for an inode resulting from NFS filehandle conversion or
* creating a dentry for a given inode, often in the process of * similar open by handle operations. The returned dentry may be anonymous,
* mapping a filehandle to a dentry. The returned dentry may be * or may have a full name (if the inode was already in the cache).
* 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.
* *
* When called on a directory inode, we must ensure that * When called on a directory inode, we must ensure that the inode only ever
* the inode only ever has one dentry. If a dentry is * has one dentry. If a dentry is found, that is returned instead of
* found, that is returned instead of allocating a new one. * allocating a new one.
* *
* On successful return, the reference to the inode has been transferred * On successful return, the reference to the inode has been transferred
* to the dentry. If %NULL is returned (indicating kmalloc failure), * to the dentry. In case of an error the reference on the inode is released.
* the reference on the inode has not been 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_obtain_alias(struct inode *inode)
struct dentry * d_alloc_anon(struct inode *inode)
{ {
static const struct qstr anonstring = { .name = "" }; static const struct qstr anonstring = { .name = "" };
struct dentry *tmp; struct dentry *tmp;
struct dentry *res; struct dentry *res;
if ((res = d_find_alias(inode))) { if (!inode)
iput(inode); return ERR_PTR(-ESTALE);
return res; if (IS_ERR(inode))
} return ERR_CAST(inode);
res = d_find_alias(inode);
if (res)
goto out_iput;
tmp = d_alloc(NULL, &anonstring); tmp = d_alloc(NULL, &anonstring);
if (!tmp) if (!tmp) {
return NULL; res = ERR_PTR(-ENOMEM);
goto out_iput;
}
tmp->d_parent = tmp; /* make sure dput doesn't croak */ tmp->d_parent = tmp; /* make sure dput doesn't croak */
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
res = __d_find_alias(inode, 0); res = __d_find_alias(inode, 0);
if (!res) { if (res) {
/* attach a disconnected dentry */ spin_unlock(&dcache_lock);
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)
dput(tmp); 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; return res;
} }
EXPORT_SYMBOL_GPL(d_obtain_alias);
/** /**
* d_splice_alias - splice a disconnected dentry into the tree if one exists * 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); new = __d_find_alias(inode, 1);
if (new) { if (new) {
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
fsnotify_d_instantiate(new, inode);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
security_d_instantiate(new, inode); security_d_instantiate(new, inode);
d_rehash(dentry); d_rehash(dentry);
d_move(new, dentry); d_move(new, dentry);
iput(inode); iput(inode);
} else { } else {
/* d_instantiate takes dcache_lock, so we do it by hand */ /* already taking dcache_lock, so d_add() by hand */
list_add(&dentry->d_alias, &inode->i_dentry); __d_instantiate(dentry, inode);
dentry->d_inode = inode;
fsnotify_d_instantiate(dentry, inode);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
security_d_instantiate(dentry, inode); security_d_instantiate(dentry, inode);
d_rehash(dentry); 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 * d_instantiate() by hand because it takes dcache_lock which
* we already hold. * we already hold.
*/ */
list_add(&found->d_alias, &inode->i_dentry); __d_instantiate(found, inode);
found->d_inode = inode;
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
security_d_instantiate(found, inode); security_d_instantiate(found, inode);
return found; return found;
@ -1456,8 +1463,6 @@ out:
* d_validate - verify dentry provided from insecure source * d_validate - verify dentry provided from insecure source
* @dentry: The dentry alleged to be valid child of @dparent * @dentry: The dentry alleged to be valid child of @dparent
* @dparent: The parent dentry (known to be valid) * @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. * An insecure source has sent us a dentry, here we verify it and dget() it.
* This is used by ncpfs in its readdir implementation. * 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); 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; 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) 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 */ /* Check for loops */
ret = ERR_PTR(-ELOOP); ret = ERR_PTR(-ELOOP);
if (d_isparent(alias, dentry)) if (d_ancestor(alias, dentry))
goto out_err; goto out_err;
/* See lock_rename() */ /* See lock_rename() */
@ -1822,7 +1832,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
if (!inode) { if (!inode) {
actual = dentry; actual = dentry;
dentry->d_inode = NULL; __d_instantiate(dentry, NULL);
goto found_lock; goto found_lock;
} }
@ -2149,32 +2159,27 @@ out:
* Caller must ensure that "new_dentry" is pinned before calling is_subdir() * 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; int result;
struct dentry * saved = new_dentry;
unsigned long seq; unsigned long seq;
/* need rcu_readlock to protect against the d_parent trashing due to /* FIXME: This is old behavior, needed? Please check callers. */
* d_move if (new_dentry == old_dentry)
return 1;
/*
* Need rcu_readlock to protect against the d_parent trashing
* due to d_move
*/ */
rcu_read_lock(); rcu_read_lock();
do { do {
/* for restarting inner loop in case of seq retry */ /* for restarting inner loop in case of seq retry */
new_dentry = saved;
result = 0;
seq = read_seqbegin(&rename_lock); seq = read_seqbegin(&rename_lock);
for (;;) { if (d_ancestor(old_dentry, new_dentry))
if (new_dentry != old_dentry) {
struct dentry * parent = new_dentry->d_parent;
if (parent == new_dentry)
break;
new_dentry = parent;
continue;
}
result = 1; result = 1;
break; else
} result = 0;
} while (read_seqretry(&rename_lock, seq)); } while (read_seqretry(&rename_lock, seq));
rcu_read_unlock(); rcu_read_unlock();
@ -2344,7 +2349,6 @@ void __init vfs_caches_init(unsigned long mempages)
} }
EXPORT_SYMBOL(d_alloc); EXPORT_SYMBOL(d_alloc);
EXPORT_SYMBOL(d_alloc_anon);
EXPORT_SYMBOL(d_alloc_root); EXPORT_SYMBOL(d_alloc_root);
EXPORT_SYMBOL(d_delete); EXPORT_SYMBOL(d_delete);
EXPORT_SYMBOL(d_find_alias); EXPORT_SYMBOL(d_find_alias);

View File

@ -1805,19 +1805,19 @@ int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
} }
/* Actual function called from quotactl() */ /* 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) int remount)
{ {
struct nameidata nd; struct path path;
int error; int error;
if (remount) if (remount)
return vfs_quota_on_remount(sb, type); return vfs_quota_on_remount(sb, type);
error = path_lookup(path, LOOKUP_FOLLOW, &nd); error = kern_path(name, LOOKUP_FOLLOW, &path);
if (!error) { if (!error) {
error = vfs_quota_on_path(sb, type, format_id, &nd.path); error = vfs_quota_on_path(sb, type, format_id, &path);
path_put(&nd.path); path_put(&path);
} }
return error; return error;
} }

View File

@ -471,31 +471,26 @@ out:
*/ */
static int ecryptfs_read_super(struct super_block *sb, const char *dev_name) static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
{ {
struct path path;
int rc; int rc;
struct nameidata nd;
struct dentry *lower_root;
struct vfsmount *lower_mnt;
memset(&nd, 0, sizeof(struct nameidata)); rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
rc = path_lookup(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
if (rc) { if (rc) {
ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n"); ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n");
goto out; goto out;
} }
lower_root = nd.path.dentry; ecryptfs_set_superblock_lower(sb, path.dentry->d_sb);
lower_mnt = nd.path.mnt; sb->s_maxbytes = path.dentry->d_sb->s_maxbytes;
ecryptfs_set_superblock_lower(sb, lower_root->d_sb); sb->s_blocksize = path.dentry->d_sb->s_blocksize;
sb->s_maxbytes = lower_root->d_sb->s_maxbytes; ecryptfs_set_dentry_lower(sb->s_root, path.dentry);
sb->s_blocksize = lower_root->d_sb->s_blocksize; ecryptfs_set_dentry_lower_mnt(sb->s_root, path.mnt);
ecryptfs_set_dentry_lower(sb->s_root, lower_root); rc = ecryptfs_interpose(path.dentry, sb->s_root, sb, 0);
ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt);
rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0);
if (rc) if (rc)
goto out_free; goto out_free;
rc = 0; rc = 0;
goto out; goto out;
out_free: out_free:
path_put(&nd.path); path_put(&path);
out: out:
return rc; return rc;
} }

View File

@ -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 *efs_get_parent(struct dentry *child)
{ {
struct dentry *parent; struct dentry *parent = ERR_PTR(-ENOENT);
struct inode *inode;
efs_ino_t ino; efs_ino_t ino;
long error;
lock_kernel(); lock_kernel();
error = -ENOENT;
ino = efs_find_entry(child->d_inode, "..", 2); ino = efs_find_entry(child->d_inode, "..", 2);
if (!ino) if (ino)
goto fail; parent = d_obtain_alias(efs_iget(child->d_inode->i_sb, ino));
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;
unlock_kernel(); unlock_kernel();
return parent; return parent;
fail_iput:
iput(inode);
fail:
unlock_kernel();
return ERR_PTR(error);
} }

View File

@ -94,9 +94,8 @@ find_disconnected_root(struct dentry *dentry)
* It may already be, as the flag isn't always updated when connection happens. * It may already be, as the flag isn't always updated when connection happens.
*/ */
static int 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 noprogress = 0;
int err = -ESTALE; int err = -ESTALE;
@ -281,13 +280,14 @@ static int get_name(struct vfsmount *mnt, struct dentry *dentry,
int old_seq = buffer.sequence; int old_seq = buffer.sequence;
error = vfs_readdir(file, filldir_one, &buffer); error = vfs_readdir(file, filldir_one, &buffer);
if (buffer.found) {
error = 0;
break;
}
if (error < 0) if (error < 0)
break; break;
error = 0;
if (buffer.found)
break;
error = -ENOENT; error = -ENOENT;
if (old_seq == buffer.sequence) if (old_seq == buffer.sequence)
break; 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; const struct export_operations *nop = mnt->mnt_sb->s_export_op;
struct dentry *result, *alias; struct dentry *result, *alias;
char nbuf[NAME_MAX+1];
int err; int err;
/* /*
* Try to get any dentry for the given file handle from the filesystem. * 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); result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
if (!result)
result = ERR_PTR(-ESTALE);
if (IS_ERR(result)) if (IS_ERR(result))
return result; return result;
@ -381,7 +380,7 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
* filesystem root. * filesystem root.
*/ */
if (result->d_flags & DCACHE_DISCONNECTED) { if (result->d_flags & DCACHE_DISCONNECTED) {
err = reconnect_path(mnt, result); err = reconnect_path(mnt, result, nbuf);
if (err) if (err)
goto err_result; 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. * It's not a directory. Life is a little more complicated.
*/ */
struct dentry *target_dir, *nresult; struct dentry *target_dir, *nresult;
char nbuf[NAME_MAX+1];
/* /*
* See if either the dentry we just got from the filesystem * 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, target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
fh_len, fileid_type); fh_len, fileid_type);
if (!target_dir)
goto err_result;
err = PTR_ERR(target_dir); err = PTR_ERR(target_dir);
if (IS_ERR(target_dir)) if (IS_ERR(target_dir))
goto err_result; 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 * connected to the filesystem root. The VFS really doesn't
* like disconnected directories.. * like disconnected directories..
*/ */
err = reconnect_path(mnt, target_dir); err = reconnect_path(mnt, target_dir, nbuf);
if (err) { if (err) {
dput(target_dir); dput(target_dir);
goto err_result; goto err_result;

View File

@ -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. * (as a parameter - res_dir). Page is returned mapped and unlocked.
* Entry is guaranteed to be valid. * Entry is guaranteed to be valid.
*/ */
struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir, struct ext2_dir_entry_2 *ext2_find_entry (struct inode * dir,
struct dentry *dentry, struct page ** res_page) struct qstr *child, struct page ** res_page)
{ {
const char *name = dentry->d_name.name; const char *name = child->name;
int namelen = dentry->d_name.len; int namelen = child->len;
unsigned reclen = EXT2_DIR_REC_LEN(namelen); unsigned reclen = EXT2_DIR_REC_LEN(namelen);
unsigned long start, n; unsigned long start, n;
unsigned long npages = dir_pages(dir); 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; 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; ino_t res = 0;
struct ext2_dir_entry_2 * de; struct ext2_dir_entry_2 *de;
struct page *page; struct page *page;
de = ext2_find_entry (dir, dentry, &page); de = ext2_find_entry (dir, child, &page);
if (de) { if (de) {
res = le32_to_cpu(de->inode); res = le32_to_cpu(de->inode);
ext2_put_page(page); ext2_put_page(page);

View File

@ -105,9 +105,9 @@ extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_wind
/* dir.c */ /* dir.c */
extern int ext2_add_link (struct dentry *, struct inode *); 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 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_delete_entry (struct ext2_dir_entry_2 *, struct page *);
extern int ext2_empty_dir (struct inode *); extern int ext2_empty_dir (struct inode *);
extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);

View File

@ -60,7 +60,7 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
if (dentry->d_name.len > EXT2_NAME_LEN) if (dentry->d_name.len > EXT2_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
ino = ext2_inode_by_name(dir, dentry); ino = ext2_inode_by_name(dir, &dentry->d_name);
inode = NULL; inode = NULL;
if (ino) { if (ino) {
inode = ext2_iget(dir->i_sb, 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) struct dentry *ext2_get_parent(struct dentry *child)
{ {
unsigned long ino; struct qstr dotdot = {.name = "..", .len = 2};
struct dentry *parent; unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot);
struct inode *inode;
struct dentry dotdot;
dotdot.d_name.name = "..";
dotdot.d_name.len = 2;
ino = ext2_inode_by_name(child->d_inode, &dotdot);
if (!ino) if (!ino)
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
inode = ext2_iget(child->d_inode->i_sb, ino); return d_obtain_alias(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;
} }
/* /*
@ -257,7 +241,7 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry)
struct page * page; struct page * page;
int err = -ENOENT; int err = -ENOENT;
de = ext2_find_entry (dir, dentry, &page); de = ext2_find_entry (dir, &dentry->d_name, &page);
if (!de) if (!de)
goto out; 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; struct ext2_dir_entry_2 * old_de;
int err = -ENOENT; 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) if (!old_de)
goto out; goto out;
@ -319,7 +303,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
goto out_dir; goto out_dir;
err = -ENOENT; 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) if (!new_de)
goto out_dir; goto out_dir;
inode_inc_link_count(old_inode); inode_inc_link_count(old_inode);

View File

@ -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 void dx_set_limit (struct dx_entry *entries, unsigned value);
static unsigned dx_root_limit (struct inode *dir, unsigned infosize); static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
static unsigned dx_node_limit (struct inode *dir); 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 inode *dir,
struct dx_hash_info *hinfo, struct dx_hash_info *hinfo,
struct dx_frame *frame, 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 *frame,
struct dx_frame *frames, struct dx_frame *frames,
__u32 *start_hash); __u32 *start_hash);
static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, static struct buffer_head * ext3_dx_find_entry(struct inode *dir,
struct ext3_dir_entry_2 **res_dir, int *err); struct qstr *entry, struct ext3_dir_entry_2 **res_dir,
int *err);
static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
struct inode *inode); struct inode *inode);
@ -342,7 +343,7 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
* back to userspace. * back to userspace.
*/ */
static struct dx_frame * 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) struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
{ {
unsigned count, indirect; unsigned count, indirect;
@ -353,8 +354,6 @@ dx_probe(struct dentry *dentry, struct inode *dir,
u32 hash; u32 hash;
frame->bh = NULL; frame->bh = NULL;
if (dentry)
dir = dentry->d_parent->d_inode;
if (!(bh = ext3_bread (NULL,dir, 0, 0, err))) if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
goto fail; goto fail;
root = (struct dx_root *) bh->b_data; 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->hash_version = root->info.hash_version;
hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed; hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed;
if (dentry) if (entry)
ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo); ext3fs_dirhash(entry->name, entry->len, hinfo);
hash = hinfo->hash; hash = hinfo->hash;
if (root->info.unused_flags & 1) { 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, static inline int search_dirblock(struct buffer_head * bh,
struct inode *dir, struct inode *dir,
struct dentry *dentry, struct qstr *child,
unsigned long offset, unsigned long offset,
struct ext3_dir_entry_2 ** res_dir) struct ext3_dir_entry_2 ** res_dir)
{ {
struct ext3_dir_entry_2 * de; struct ext3_dir_entry_2 * de;
char * dlimit; char * dlimit;
int de_len; int de_len;
const char *name = dentry->d_name.name; const char *name = child->name;
int namelen = dentry->d_name.len; int namelen = child->len;
de = (struct ext3_dir_entry_2 *) bh->b_data; de = (struct ext3_dir_entry_2 *) bh->b_data;
dlimit = bh->b_data + dir->i_sb->s_blocksize; 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 * The returned buffer_head has ->b_count elevated. The caller is expected
* to brelse() it when appropriate. * to brelse() it when appropriate.
*/ */
static struct buffer_head * ext3_find_entry (struct dentry *dentry, static struct buffer_head *ext3_find_entry(struct inode *dir,
struct ext3_dir_entry_2 ** res_dir) struct qstr *entry,
struct ext3_dir_entry_2 **res_dir)
{ {
struct super_block * sb; struct super_block * sb;
struct buffer_head * bh_use[NAMEI_RA_SIZE]; struct buffer_head * bh_use[NAMEI_RA_SIZE];
@ -863,16 +863,15 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
buffer */ buffer */
int num = 0; int num = 0;
int nblocks, i, err; int nblocks, i, err;
struct inode *dir = dentry->d_parent->d_inode;
int namelen; int namelen;
*res_dir = NULL; *res_dir = NULL;
sb = dir->i_sb; sb = dir->i_sb;
namelen = dentry->d_name.len; namelen = entry->len;
if (namelen > EXT3_NAME_LEN) if (namelen > EXT3_NAME_LEN)
return NULL; return NULL;
if (is_dx(dir)) { 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, * On success, or if the error was file not found,
* return. Otherwise, fall back to doing a search the * return. Otherwise, fall back to doing a search the
@ -923,7 +922,7 @@ restart:
brelse(bh); brelse(bh);
goto next; goto next;
} }
i = search_dirblock(bh, dir, dentry, i = search_dirblock(bh, dir, entry,
block << EXT3_BLOCK_SIZE_BITS(sb), res_dir); block << EXT3_BLOCK_SIZE_BITS(sb), res_dir);
if (i == 1) { if (i == 1) {
EXT3_I(dir)->i_dir_start_lookup = block; EXT3_I(dir)->i_dir_start_lookup = block;
@ -957,8 +956,9 @@ cleanup_and_exit:
return ret; return ret;
} }
static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, static struct buffer_head * ext3_dx_find_entry(struct inode *dir,
struct ext3_dir_entry_2 **res_dir, int *err) struct qstr *entry, struct ext3_dir_entry_2 **res_dir,
int *err)
{ {
struct super_block * sb; struct super_block * sb;
struct dx_hash_info hinfo; struct dx_hash_info hinfo;
@ -968,14 +968,13 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
struct buffer_head *bh; struct buffer_head *bh;
unsigned long block; unsigned long block;
int retval; int retval;
int namelen = dentry->d_name.len; int namelen = entry->len;
const u8 *name = dentry->d_name.name; const u8 *name = entry->name;
struct inode *dir = dentry->d_parent->d_inode;
sb = dir->i_sb; sb = dir->i_sb;
/* NFS may look up ".." - look at dx_root directory block */ /* NFS may look up ".." - look at dx_root directory block */
if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){ if (namelen > 2 || name[0] != '.'|| (namelen == 2 && name[1] != '.')) {
if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err))) if (!(frame = dx_probe(entry, dir, &hinfo, frames, err)))
return NULL; return NULL;
} else { } else {
frame = frames; 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) if (dentry->d_name.len > EXT3_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
bh = ext3_find_entry(dentry, &de); bh = ext3_find_entry(dir, &dentry->d_name, &de);
inode = NULL; inode = NULL;
if (bh) { if (bh) {
unsigned long ino = le32_to_cpu(de->inode); 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) struct dentry *ext3_get_parent(struct dentry *child)
{ {
unsigned long ino; unsigned long ino;
struct dentry *parent; struct qstr dotdot = {.name = "..", .len = 2};
struct inode *inode;
struct dentry dotdot;
struct ext3_dir_entry_2 * de; struct ext3_dir_entry_2 * de;
struct buffer_head *bh; struct buffer_head *bh;
dotdot.d_name.name = ".."; bh = ext3_find_entry(child->d_inode, &dotdot, &de);
dotdot.d_name.len = 2;
dotdot.d_parent = child; /* confusing, isn't it! */
bh = ext3_find_entry(&dotdot, &de);
inode = NULL;
if (!bh) if (!bh)
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
ino = le32_to_cpu(de->inode); ino = le32_to_cpu(de->inode);
@ -1080,16 +1072,7 @@ struct dentry *ext3_get_parent(struct dentry *child)
return ERR_PTR(-EIO); return ERR_PTR(-EIO);
} }
inode = ext3_iget(child->d_inode->i_sb, ino); return d_obtain_alias(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;
} }
#define S_SHIFT 12 #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; struct ext3_dir_entry_2 *de;
int err; int err;
frame = dx_probe(dentry, NULL, &hinfo, frames, &err); frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err);
if (!frame) if (!frame)
return err; return err;
entries = frame->entries; entries = frame->entries;
@ -2056,7 +2039,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
return PTR_ERR(handle); return PTR_ERR(handle);
retval = -ENOENT; retval = -ENOENT;
bh = ext3_find_entry (dentry, &de); bh = ext3_find_entry(dir, &dentry->d_name, &de);
if (!bh) if (!bh)
goto end_rmdir; goto end_rmdir;
@ -2118,7 +2101,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
handle->h_sync = 1; handle->h_sync = 1;
retval = -ENOENT; retval = -ENOENT;
bh = ext3_find_entry (dentry, &de); bh = ext3_find_entry(dir, &dentry->d_name, &de);
if (!bh) if (!bh)
goto end_unlink; 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)) if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
handle->h_sync = 1; 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. * Check for inode number is _not_ due to possible IO errors.
* We might rmdir the source, keep it as pwd of some process * 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; goto end_rename;
new_inode = new_dentry->d_inode; 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_bh) {
if (!new_inode) { if (!new_inode) {
brelse (new_bh); 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 buffer_head *old_bh2;
struct ext3_dir_entry_2 *old_de2; 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) { if (old_bh2) {
retval = ext3_delete_entry(handle, old_dir, retval = ext3_delete_entry(handle, old_dir,
old_de2, old_bh2); old_de2, old_bh2);

View File

@ -2794,30 +2794,30 @@ static int ext3_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on * Standard function to be called on quota_on
*/ */
static int ext3_quota_on(struct super_block *sb, int type, int format_id, static int ext3_quota_on(struct super_block *sb, int type, int format_id,
char *path, int remount) char *name, int remount)
{ {
int err; int err;
struct nameidata nd; struct path path;
if (!test_opt(sb, QUOTA)) if (!test_opt(sb, QUOTA))
return -EINVAL; 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) 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) if (err)
return err; return err;
/* Quotafile not on the same filesystem? */ /* Quotafile not on the same filesystem? */
if (nd.path.mnt->mnt_sb != sb) { if (path.mnt->mnt_sb != sb) {
path_put(&nd.path); path_put(&path);
return -EXDEV; return -EXDEV;
} }
/* Journaling quota? */ /* Journaling quota? */
if (EXT3_SB(sb)->s_qf_names[type]) { if (EXT3_SB(sb)->s_qf_names[type]) {
/* Quotafile not of fs root? */ /* 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 printk(KERN_WARNING
"EXT3-fs: Quota file not on filesystem root. " "EXT3-fs: Quota file not on filesystem root. "
"Journaled quota will not work.\n"); "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 * When we journal data on quota file, we have to flush journal to see
* all updates to the file when we bypass pagecache... * 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 * We don't need to lock updates but journal_flush() could
* otherwise be livelocked... * 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); err = vfs_quota_on_path(sb, type, format_id, &path);
path_put(&nd.path); path_put(&path);
return err; return err;
} }

View File

@ -1083,16 +1083,7 @@ struct dentry *ext4_get_parent(struct dentry *child)
return ERR_PTR(-EIO); return ERR_PTR(-EIO);
} }
inode = ext4_iget(child->d_inode->i_sb, ino); return d_obtain_alias(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;
} }
#define S_SHIFT 12 #define S_SHIFT 12

View File

@ -3328,30 +3328,30 @@ static int ext4_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on * Standard function to be called on quota_on
*/ */
static int ext4_quota_on(struct super_block *sb, int type, int format_id, static int ext4_quota_on(struct super_block *sb, int type, int format_id,
char *path, int remount) char *name, int remount)
{ {
int err; int err;
struct nameidata nd; struct path path;
if (!test_opt(sb, QUOTA)) if (!test_opt(sb, QUOTA))
return -EINVAL; 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) 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) if (err)
return err; return err;
/* Quotafile not on the same filesystem? */ /* Quotafile not on the same filesystem? */
if (nd.path.mnt->mnt_sb != sb) { if (path.mnt->mnt_sb != sb) {
path_put(&nd.path); path_put(&path);
return -EXDEV; return -EXDEV;
} }
/* Journaling quota? */ /* Journaling quota? */
if (EXT4_SB(sb)->s_qf_names[type]) { if (EXT4_SB(sb)->s_qf_names[type]) {
/* Quotafile not in fs root? */ /* 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 printk(KERN_WARNING
"EXT4-fs: Quota file not on filesystem root. " "EXT4-fs: Quota file not on filesystem root. "
"Journaled quota will not work.\n"); "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 * When we journal data on quota file, we have to flush journal to see
* all updates to the file when we bypass pagecache... * 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 * We don't need to lock updates but journal_flush() could
* otherwise be livelocked... * 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); err = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
if (err) { if (err) {
path_put(&nd.path); path_put(&path);
return err; return err;
} }
} }
err = vfs_quota_on_path(sb, type, format_id, &nd.path); err = vfs_quota_on_path(sb, type, format_id, &path);
path_put(&nd.path); path_put(&path);
return err; return err;
} }

View File

@ -839,6 +839,7 @@ const struct file_operations fat_dir_operations = {
.compat_ioctl = fat_compat_dir_ioctl, .compat_ioctl = fat_compat_dir_ioctl,
#endif #endif
.fsync = file_fsync, .fsync = file_fsync,
.llseek = generic_file_llseek,
}; };
static int fat_get_short_entry(struct inode *dir, loff_t *pos, static int fat_get_short_entry(struct inode *dir, loff_t *pos,

View File

@ -681,33 +681,24 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb,
inode = NULL; 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. * For now, do nothing if the inode is not found.
* If possible, get a well-connected one *
* 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); result = d_obtain_alias(inode);
if (result == NULL) { if (!IS_ERR(result))
iput(inode); result->d_op = sb->s_root->d_op;
return ERR_PTR(-ENOMEM);
}
result->d_op = sb->s_root->d_op;
return result; return result;
} }
@ -754,15 +745,8 @@ static struct dentry *fat_get_parent(struct dentry *child)
} }
inode = fat_build_inode(sb, de, i_pos); inode = fat_build_inode(sb, de, i_pos);
brelse(bh); brelse(bh);
if (IS_ERR(inode)) {
parent = ERR_CAST(inode); parent = d_obtain_alias(inode);
goto out;
}
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
parent = ERR_PTR(-ENOMEM);
}
out: out:
unlock_super(sb); unlock_super(sb);

View File

@ -596,12 +596,8 @@ static struct dentry *fuse_get_dentry(struct super_block *sb,
if (inode->i_generation != handle->generation) if (inode->i_generation != handle->generation)
goto out_iput; goto out_iput;
entry = d_alloc_anon(inode); entry = d_obtain_alias(inode);
err = -ENOMEM; if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID) {
if (!entry)
goto out_iput;
if (get_node_id(inode) != FUSE_ROOT_ID) {
entry->d_op = &fuse_dentry_operations; entry->d_op = &fuse_dentry_operations;
fuse_invalidate_entry_cache(entry); fuse_invalidate_entry_cache(entry);
} }
@ -696,17 +692,14 @@ static struct dentry *fuse_get_parent(struct dentry *child)
name.name = ".."; name.name = "..";
err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode), err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode),
&name, &outarg, &inode); &name, &outarg, &inode);
if (err && err != -ENOENT) if (err) {
if (err == -ENOENT)
return ERR_PTR(-ESTALE);
return ERR_PTR(err); 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; parent->d_op = &fuse_dentry_operations;
fuse_invalidate_entry_cache(parent); fuse_invalidate_entry_cache(parent);
} }

View File

@ -130,28 +130,17 @@ static int gfs2_get_name(struct dentry *parent, char *name,
static struct dentry *gfs2_get_parent(struct dentry *child) static struct dentry *gfs2_get_parent(struct dentry *child)
{ {
struct qstr dotdot; struct qstr dotdot;
struct inode *inode;
struct dentry *dentry; 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 * XXX(hch): it would be a good idea to keep this around as a
* have to return that as a(n invalid) pointer to dentry. * static variable.
*/ */
if (IS_ERR(inode)) gfs2_str2qstr(&dotdot, "..");
return ERR_CAST(inode);
dentry = d_alloc_anon(inode); dentry = d_obtain_alias(gfs2_lookupi(child->d_inode, &dotdot, 1));
if (!dentry) { if (!IS_ERR(dentry))
iput(inode); dentry->d_op = &gfs2_dops;
return ERR_PTR(-ENOMEM);
}
dentry->d_op = &gfs2_dops;
return dentry; return dentry;
} }
@ -233,13 +222,9 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
gfs2_glock_dq_uninit(&i_gh); gfs2_glock_dq_uninit(&i_gh);
out_inode: out_inode:
dentry = d_alloc_anon(inode); dentry = d_obtain_alias(inode);
if (!dentry) { if (!IS_ERR(dentry))
iput(inode); dentry->d_op = &gfs2_dops;
return ERR_PTR(-ENOMEM);
}
dentry->d_op = &gfs2_dops;
return dentry; return dentry;
fail_rgd: fail_rgd:

View File

@ -69,7 +69,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
mark_inode_dirty(inode); mark_inode_dirty(inode);
break; break;
} else if (PTR_ERR(inode) != -EEXIST || } else if (PTR_ERR(inode) != -EEXIST ||
(nd && (nd->intent.open.flags & O_EXCL))) { (nd && nd->flags & LOOKUP_EXCL)) {
gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs);
return PTR_ERR(inode); return PTR_ERR(inode);
} }

View File

@ -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) static int hfs_file_open(struct inode *inode, struct file *file)
{ {
if (HFS_IS_RSRC(inode)) if (HFS_IS_RSRC(inode))
@ -616,7 +609,6 @@ static const struct inode_operations hfs_file_inode_operations = {
.lookup = hfs_file_lookup, .lookup = hfs_file_lookup,
.truncate = hfs_file_truncate, .truncate = hfs_file_truncate,
.setattr = hfs_inode_setattr, .setattr = hfs_inode_setattr,
.permission = hfs_permission,
.setxattr = hfs_setxattr, .setxattr = hfs_setxattr,
.getxattr = hfs_getxattr, .getxattr = hfs_getxattr,
.listxattr = hfs_listxattr, .listxattr = hfs_listxattr,

View File

@ -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); 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) static int hfsplus_file_open(struct inode *inode, struct file *file)
{ {
if (HFSPLUS_IS_RSRC(inode)) 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 = { static const struct inode_operations hfsplus_file_inode_operations = {
.lookup = hfsplus_file_lookup, .lookup = hfsplus_file_lookup,
.truncate = hfsplus_file_truncate, .truncate = hfsplus_file_truncate,
.permission = hfsplus_permission,
.setxattr = hfsplus_setxattr, .setxattr = hfsplus_setxattr,
.getxattr = hfsplus_getxattr, .getxattr = hfsplus_getxattr,
.listxattr = hfsplus_listxattr, .listxattr = hfsplus_listxattr,

View File

@ -143,5 +143,5 @@ const struct file_operations hpfs_file_ops =
const struct inode_operations hpfs_file_iops = const struct inode_operations hpfs_file_iops =
{ {
.truncate = hpfs_truncate, .truncate = hpfs_truncate,
.setattr = hpfs_notify_change, .setattr = hpfs_setattr,
}; };

View File

@ -275,7 +275,7 @@ void hpfs_init_inode(struct inode *);
void hpfs_read_inode(struct inode *); void hpfs_read_inode(struct inode *);
void hpfs_write_inode(struct inode *); void hpfs_write_inode(struct inode *);
void hpfs_write_inode_nolock(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_write_if_changed(struct inode *);
void hpfs_delete_inode(struct inode *); void hpfs_delete_inode(struct inode *);

View File

@ -260,19 +260,28 @@ void hpfs_write_inode_nolock(struct inode *i)
brelse(bh); 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; struct inode *inode = dentry->d_inode;
int error=0; int error = -EINVAL;
lock_kernel(); lock_kernel();
if ( ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) || if (inode->i_ino == hpfs_sb(inode->i_sb)->sb_root)
(hpfs_sb(inode->i_sb)->sb_root == inode->i_ino) ) { goto out_unlock;
error = -EINVAL; if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size)
} else if ((error = inode_change_ok(inode, attr))) { goto out_unlock;
} else if ((error = inode_setattr(inode, attr))) {
} else { error = inode_change_ok(inode, attr);
hpfs_write_inode(inode); if (error)
} goto out_unlock;
error = inode_setattr(inode, attr);
if (error)
goto out_unlock;
hpfs_write_inode(inode);
out_unlock:
unlock_kernel(); unlock_kernel();
return error; return error;
} }

View File

@ -669,5 +669,5 @@ const struct inode_operations hpfs_dir_iops =
.rmdir = hpfs_rmdir, .rmdir = hpfs_rmdir,
.mknod = hpfs_mknod, .mknod = hpfs_mknod,
.rename = hpfs_rename, .rename = hpfs_rename,
.setattr = hpfs_notify_change, .setattr = hpfs_setattr,
}; };

View File

@ -22,7 +22,7 @@ isofs_export_iget(struct super_block *sb,
__u32 generation) __u32 generation)
{ {
struct inode *inode; struct inode *inode;
struct dentry *result;
if (block == 0) if (block == 0)
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
inode = isofs_iget(sb, block, offset); inode = isofs_iget(sb, block, offset);
@ -32,12 +32,7 @@ isofs_export_iget(struct super_block *sb,
iput(inode); iput(inode);
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
} }
result = d_alloc_anon(inode); return d_obtain_alias(inode);
if (!result) {
iput(inode);
return ERR_PTR(-ENOMEM);
}
return result;
} }
/* This function is surprisingly simple. The trick is understanding /* 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; unsigned long parent_offset = 0;
struct inode *child_inode = child->d_inode; struct inode *child_inode = child->d_inode;
struct iso_inode_info *e_child_inode = ISOFS_I(child_inode); struct iso_inode_info *e_child_inode = ISOFS_I(child_inode);
struct inode *parent_inode = NULL;
struct iso_directory_record *de = NULL; struct iso_directory_record *de = NULL;
struct buffer_head * bh = NULL; struct buffer_head * bh = NULL;
struct dentry *rv = NULL; struct dentry *rv = NULL;
@ -104,28 +98,11 @@ static struct dentry *isofs_export_get_parent(struct dentry *child)
/* Normalize */ /* Normalize */
isofs_normalize_block_and_offset(de, &parent_block, &parent_offset); isofs_normalize_block_and_offset(de, &parent_block, &parent_offset);
/* Get the inode. */ rv = d_obtain_alias(isofs_iget(child_inode->i_sb, parent_block,
parent_inode = isofs_iget(child_inode->i_sb, parent_offset));
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;
}
out: out:
if (bh) { if (bh)
brelse(bh); brelse(bh);
}
return rv; return rv;
} }

View File

@ -39,7 +39,8 @@ const struct file_operations jffs2_dir_operations =
.read = generic_read_dir, .read = generic_read_dir,
.readdir = jffs2_readdir, .readdir = jffs2_readdir,
.unlocked_ioctl=jffs2_ioctl, .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 d_splice_alias(inode, target);
return NULL;
} }
/***********************************************************************/ /***********************************************************************/

View File

@ -22,6 +22,7 @@
#include <linux/mtd/super.h> #include <linux/mtd/super.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/exportfs.h>
#include "compr.h" #include "compr.h"
#include "nodelist.h" #include "nodelist.h"
@ -62,6 +63,52 @@ static int jffs2_sync_fs(struct super_block *sb, int wait)
return 0; 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 = static const struct super_operations jffs2_super_operations =
{ {
.alloc_inode = jffs2_alloc_inode, .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); spin_lock_init(&c->inocache_lock);
sb->s_op = &jffs2_super_operations; sb->s_op = &jffs2_super_operations;
sb->s_export_op = &jffs2_export_ops;
sb->s_flags = sb->s_flags | MS_NOATIME; sb->s_flags = sb->s_flags | MS_NOATIME;
sb->s_xattr = jffs2_xattr_handlers; sb->s_xattr = jffs2_xattr_handlers;
#ifdef CONFIG_JFFS2_FS_POSIX_ACL #ifdef CONFIG_JFFS2_FS_POSIX_ACL

View File

@ -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 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; unsigned long parent_ino;
parent_ino = parent_ino =
le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot); 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 = { const struct inode_operations jfs_dir_inode_operations = {
@ -1560,6 +1547,7 @@ const struct file_operations jfs_dir_operations = {
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = jfs_compat_ioctl, .compat_ioctl = jfs_compat_ioctl,
#endif #endif
.llseek = generic_file_llseek,
}; };
static int jfs_ci_hash(struct dentry *dir, struct qstr *this) static int jfs_ci_hash(struct dentry *dir, struct qstr *this)

View File

@ -732,28 +732,6 @@ out:
return ret; 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 * generic_fh_to_dentry - generic helper for the fh_to_dentry export operation
* @sb: filesystem to do the file handle conversion on * @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; break;
} }
return exportfs_d_alloc(inode); return d_obtain_alias(inode);
} }
EXPORT_SYMBOL_GPL(generic_fh_to_dentry); 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; break;
} }
return exportfs_d_alloc(inode); return d_obtain_alias(inode);
} }
EXPORT_SYMBOL_GPL(generic_fh_to_parent); EXPORT_SYMBOL_GPL(generic_fh_to_parent);

View File

@ -212,8 +212,7 @@ int generic_permission(struct inode *inode, int mask,
* Read/write DACs are always overridable. * Read/write DACs are always overridable.
* Executable DACs are overridable if at least one exec bit is set. * Executable DACs are overridable if at least one exec bit is set.
*/ */
if (!(mask & MAY_EXEC) || if (!(mask & MAY_EXEC) || execute_ok(inode))
(inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
if (capable(CAP_DAC_OVERRIDE)) if (capable(CAP_DAC_OVERRIDE))
return 0; return 0;
@ -249,23 +248,11 @@ int inode_permission(struct inode *inode, int mask)
} }
/* Ordinary permission routines do not understand MAY_APPEND. */ /* 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); retval = inode->i_op->permission(inode, mask);
if (!retval) { else
/*
* 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 {
retval = generic_permission(inode, mask, NULL); retval = generic_permission(inode, mask, NULL);
}
if (retval) if (retval)
return 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); 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 * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair
* @dentry: pointer to dentry of the base directory * @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 * path_lookup_open - lookup a file path with open intent
* @dfd: the directory to use as base, or AT_FDCWD * @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, int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags,
struct nameidata *nd, int open_flags) struct nameidata *nd, int open_flags)
{ {
return __path_lookup_intent_open(dfd, name, lookup_flags, nd, struct file *filp = get_empty_filp();
open_flags, 0); int err;
}
/** if (filp == NULL)
* path_lookup_create - lookup a file path with open + create intent return -ENFILE;
* @dfd: the directory to use as base, or AT_FDCWD nd->intent.open.file = filp;
* @name: pointer to file name nd->intent.open.flags = open_flags;
* @lookup_flags: lookup intent flags nd->intent.open.create_mode = 0;
* @nd: pointer to nameidata err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd);
* @open_flags: open intent flags if (IS_ERR(nd->intent.open.file)) {
* @create_mode: create intent flags if (err == 0) {
*/ err = PTR_ERR(nd->intent.open.file);
static int path_lookup_create(int dfd, const char *name, path_put(&nd->path);
unsigned int lookup_flags, struct nameidata *nd, }
int open_flags, int create_mode) } else if (err != 0)
{ release_open_intent(nd);
return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE, return err;
nd, open_flags, create_mode);
} }
static struct dentry *__lookup_hash(struct qstr *name, 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); mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
for (p = p1; p->d_parent != p; p = p->d_parent) { p = d_ancestor(p2, p1);
if (p->d_parent == p2) { if (p) {
mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT);
mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD); mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD);
return p; return p;
}
} }
for (p = p2; p->d_parent != p; p = p->d_parent) { p = d_ancestor(p1, p2);
if (p->d_parent == p1) { if (p) {
mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD);
return p; return p;
}
} }
mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); 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. * Create - we need to know the parent.
*/ */
error = path_lookup_create(dfd, pathname, LOOKUP_PARENT, error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
&nd, flag, mode);
if (error) if (error)
return ERR_PTR(error); return ERR_PTR(error);
@ -1714,10 +1682,20 @@ struct file *do_filp_open(int dfd, const char *pathname,
*/ */
error = -EISDIR; error = -EISDIR;
if (nd.last_type != LAST_NORM || nd.last.name[nd.last.len]) 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; dir = nd.path.dentry;
nd.flags &= ~LOOKUP_PARENT; 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); mutex_lock(&dir->d_inode->i_mutex);
path.dentry = lookup_hash(&nd); path.dentry = lookup_hash(&nd);
path.mnt = nd.path.mnt; path.mnt = nd.path.mnt;
@ -1822,6 +1800,7 @@ exit_dput:
exit: exit:
if (!IS_ERR(nd.intent.open.file)) if (!IS_ERR(nd.intent.open.file))
release_open_intent(&nd); release_open_intent(&nd);
exit_parent:
path_put(&nd.path); path_put(&nd.path);
return ERR_PTR(error); return ERR_PTR(error);
@ -1914,7 +1893,7 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
if (nd->last_type != LAST_NORM) if (nd->last_type != LAST_NORM)
goto fail; goto fail;
nd->flags &= ~LOOKUP_PARENT; nd->flags &= ~LOOKUP_PARENT;
nd->flags |= LOOKUP_CREATE; nd->flags |= LOOKUP_CREATE | LOOKUP_EXCL;
nd->intent.open.flags = O_EXCL; nd->intent.open.flags = O_EXCL;
/* /*
@ -2178,16 +2157,19 @@ static long do_rmdir(int dfd, const char __user *pathname)
return error; return error;
switch(nd.last_type) { switch(nd.last_type) {
case LAST_DOTDOT: case LAST_DOTDOT:
error = -ENOTEMPTY; error = -ENOTEMPTY;
goto exit1; goto exit1;
case LAST_DOT: case LAST_DOT:
error = -EINVAL; error = -EINVAL;
goto exit1; goto exit1;
case LAST_ROOT: case LAST_ROOT:
error = -EBUSY; error = -EBUSY;
goto exit1; goto exit1;
} }
nd.flags &= ~LOOKUP_PARENT;
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
dentry = lookup_hash(&nd); dentry = lookup_hash(&nd);
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
@ -2265,6 +2247,9 @@ static long do_unlinkat(int dfd, const char __user *pathname)
error = -EISDIR; error = -EISDIR;
if (nd.last_type != LAST_NORM) if (nd.last_type != LAST_NORM)
goto exit1; goto exit1;
nd.flags &= ~LOOKUP_PARENT;
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
dentry = lookup_hash(&nd); dentry = lookup_hash(&nd);
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
@ -2654,6 +2639,10 @@ asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
if (newnd.last_type != LAST_NORM) if (newnd.last_type != LAST_NORM)
goto exit2; goto exit2;
oldnd.flags &= ~LOOKUP_PARENT;
newnd.flags &= ~LOOKUP_PARENT;
newnd.flags |= LOOKUP_RENAME_TARGET;
trap = lock_rename(new_dir, old_dir); trap = lock_rename(new_dir, old_dir);
old_dentry = lookup_hash(&oldnd); old_dentry = lookup_hash(&oldnd);
@ -2855,6 +2844,7 @@ EXPORT_SYMBOL(__page_symlink);
EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink);
EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(page_symlink_inode_operations);
EXPORT_SYMBOL(path_lookup); EXPORT_SYMBOL(path_lookup);
EXPORT_SYMBOL(kern_path);
EXPORT_SYMBOL(vfs_path_lookup); EXPORT_SYMBOL(vfs_path_lookup);
EXPORT_SYMBOL(inode_permission); EXPORT_SYMBOL(inode_permission);
EXPORT_SYMBOL(vfs_permission); EXPORT_SYMBOL(vfs_permission);

View File

@ -1167,19 +1167,19 @@ asmlinkage long sys_oldumount(char __user * name)
#endif #endif
static int mount_is_safe(struct nameidata *nd) static int mount_is_safe(struct path *path)
{ {
if (capable(CAP_SYS_ADMIN)) if (capable(CAP_SYS_ADMIN))
return 0; return 0;
return -EPERM; return -EPERM;
#ifdef notyet #ifdef notyet
if (S_ISLNK(nd->path.dentry->d_inode->i_mode)) if (S_ISLNK(path->dentry->d_inode->i_mode))
return -EPERM; return -EPERM;
if (nd->path.dentry->d_inode->i_mode & S_ISVTX) { if (path->dentry->d_inode->i_mode & S_ISVTX) {
if (current->uid != nd->path.dentry->d_inode->i_uid) if (current->uid != path->dentry->d_inode->i_uid)
return -EPERM; return -EPERM;
} }
if (vfs_permission(nd, MAY_WRITE)) if (inode_permission(path->dentry->d_inode, MAY_WRITE))
return -EPERM; return -EPERM;
return 0; return 0;
#endif #endif
@ -1425,11 +1425,10 @@ out_unlock:
/* /*
* recursively change the type of the mountpoint. * 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 recurse = flag & MS_REC;
int type = flag & ~MS_REC; int type = flag & ~MS_REC;
int err = 0; int err = 0;
@ -1437,7 +1436,7 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (nd->path.dentry != nd->path.mnt->mnt_root) if (path->dentry != path->mnt->mnt_root)
return -EINVAL; return -EINVAL;
down_write(&namespace_sem); down_write(&namespace_sem);
@ -1459,40 +1458,39 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
/* /*
* do loopback mount. * 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) int recurse)
{ {
struct nameidata old_nd; struct path old_path;
struct vfsmount *mnt = NULL; struct vfsmount *mnt = NULL;
int err = mount_is_safe(nd); int err = mount_is_safe(path);
if (err) if (err)
return err; return err;
if (!old_name || !*old_name) if (!old_name || !*old_name)
return -EINVAL; return -EINVAL;
err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd); err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
if (err) if (err)
return err; return err;
down_write(&namespace_sem); down_write(&namespace_sem);
err = -EINVAL; err = -EINVAL;
if (IS_MNT_UNBINDABLE(old_nd.path.mnt)) if (IS_MNT_UNBINDABLE(old_path.mnt))
goto out; 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; goto out;
err = -ENOMEM; err = -ENOMEM;
if (recurse) 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 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) if (!mnt)
goto out; goto out;
err = graft_tree(mnt, &nd->path); err = graft_tree(mnt, path);
if (err) { if (err) {
LIST_HEAD(umount_list); LIST_HEAD(umount_list);
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
@ -1503,7 +1501,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name,
out: out:
up_write(&namespace_sem); up_write(&namespace_sem);
path_put(&old_nd.path); path_put(&old_path);
return err; 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. * 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 * If you've mounted a non-root directory somewhere and want to do remount
* on it - tough luck. * 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) void *data)
{ {
int err; int err;
struct super_block *sb = nd->path.mnt->mnt_sb; struct super_block *sb = path->mnt->mnt_sb;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (!check_mnt(nd->path.mnt)) if (!check_mnt(path->mnt))
return -EINVAL; return -EINVAL;
if (nd->path.dentry != nd->path.mnt->mnt_root) if (path->dentry != path->mnt->mnt_root)
return -EINVAL; return -EINVAL;
down_write(&sb->s_umount); down_write(&sb->s_umount);
if (flags & MS_BIND) if (flags & MS_BIND)
err = change_mount_flags(nd->path.mnt, flags); err = change_mount_flags(path->mnt, flags);
else else
err = do_remount_sb(sb, flags, data, 0); err = do_remount_sb(sb, flags, data, 0);
if (!err) if (!err)
nd->path.mnt->mnt_flags = mnt_flags; path->mnt->mnt_flags = mnt_flags;
up_write(&sb->s_umount); up_write(&sb->s_umount);
if (!err) if (!err) {
security_sb_post_remount(nd->path.mnt, flags, data); 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; return err;
} }
@ -1568,90 +1570,85 @@ static inline int tree_contains_unbindable(struct vfsmount *mnt)
return 0; return 0;
} }
/* static int do_move_mount(struct path *path, char *old_name)
* noinline this do_mount helper to save do_mount stack space.
*/
static noinline int do_move_mount(struct nameidata *nd, char *old_name)
{ {
struct nameidata old_nd; struct path old_path, parent_path;
struct path parent_path;
struct vfsmount *p; struct vfsmount *p;
int err = 0; int err = 0;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (!old_name || !*old_name) if (!old_name || !*old_name)
return -EINVAL; return -EINVAL;
err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd); err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
if (err) if (err)
return err; return err;
down_write(&namespace_sem); down_write(&namespace_sem);
while (d_mountpoint(nd->path.dentry) && while (d_mountpoint(path->dentry) &&
follow_down(&nd->path.mnt, &nd->path.dentry)) follow_down(&path->mnt, &path->dentry))
; ;
err = -EINVAL; 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; goto out;
err = -ENOENT; err = -ENOENT;
mutex_lock(&nd->path.dentry->d_inode->i_mutex); mutex_lock(&path->dentry->d_inode->i_mutex);
if (IS_DEADDIR(nd->path.dentry->d_inode)) if (IS_DEADDIR(path->dentry->d_inode))
goto out1; goto out1;
if (!IS_ROOT(nd->path.dentry) && d_unhashed(nd->path.dentry)) if (!IS_ROOT(path->dentry) && d_unhashed(path->dentry))
goto out1; goto out1;
err = -EINVAL; err = -EINVAL;
if (old_nd.path.dentry != old_nd.path.mnt->mnt_root) if (old_path.dentry != old_path.mnt->mnt_root)
goto out1; goto out1;
if (old_nd.path.mnt == old_nd.path.mnt->mnt_parent) if (old_path.mnt == old_path.mnt->mnt_parent)
goto out1; goto out1;
if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != if (S_ISDIR(path->dentry->d_inode->i_mode) !=
S_ISDIR(old_nd.path.dentry->d_inode->i_mode)) S_ISDIR(old_path.dentry->d_inode->i_mode))
goto out1; goto out1;
/* /*
* Don't move a mount residing in a shared parent. * Don't move a mount residing in a shared parent.
*/ */
if (old_nd.path.mnt->mnt_parent && if (old_path.mnt->mnt_parent &&
IS_MNT_SHARED(old_nd.path.mnt->mnt_parent)) IS_MNT_SHARED(old_path.mnt->mnt_parent))
goto out1; goto out1;
/* /*
* Don't move a mount tree containing unbindable mounts to a destination * Don't move a mount tree containing unbindable mounts to a destination
* mount which is shared. * mount which is shared.
*/ */
if (IS_MNT_SHARED(nd->path.mnt) && if (IS_MNT_SHARED(path->mnt) &&
tree_contains_unbindable(old_nd.path.mnt)) tree_contains_unbindable(old_path.mnt))
goto out1; goto out1;
err = -ELOOP; err = -ELOOP;
for (p = nd->path.mnt; p->mnt_parent != p; p = p->mnt_parent) for (p = path->mnt; p->mnt_parent != p; p = p->mnt_parent)
if (p == old_nd.path.mnt) if (p == old_path.mnt)
goto out1; 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) if (err)
goto out1; goto out1;
/* if the mount is moved, it should no longer be expire /* if the mount is moved, it should no longer be expire
* automatically */ * automatically */
list_del_init(&old_nd.path.mnt->mnt_expire); list_del_init(&old_path.mnt->mnt_expire);
out1: out1:
mutex_unlock(&nd->path.dentry->d_inode->i_mutex); mutex_unlock(&path->dentry->d_inode->i_mutex);
out: out:
up_write(&namespace_sem); up_write(&namespace_sem);
if (!err) if (!err)
path_put(&parent_path); path_put(&parent_path);
path_put(&old_nd.path); path_put(&old_path);
return err; return err;
} }
/* /*
* create a new mount for userspace and request it to be added into the * create a new mount for userspace and request it to be added into the
* namespace's tree * 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) int mnt_flags, char *name, void *data)
{ {
struct vfsmount *mnt; struct vfsmount *mnt;
@ -1667,7 +1664,7 @@ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags,
if (IS_ERR(mnt)) if (IS_ERR(mnt))
return PTR_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, long do_mount(char *dev_name, char *dir_name, char *type_page,
unsigned long flags, void *data_page) unsigned long flags, void *data_page)
{ {
struct nameidata nd; struct path path;
int retval = 0; int retval = 0;
int mnt_flags = 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); MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT);
/* ... and get the mountpoint */ /* ... and get the mountpoint */
retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
if (retval) if (retval)
return retval; return retval;
retval = security_sb_mount(dev_name, &nd.path, retval = security_sb_mount(dev_name, &path,
type_page, flags, data_page); type_page, flags, data_page);
if (retval) if (retval)
goto dput_out; goto dput_out;
if (flags & MS_REMOUNT) if (flags & MS_REMOUNT)
retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
data_page); data_page);
else if (flags & MS_BIND) 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)) 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) else if (flags & MS_MOVE)
retval = do_move_mount(&nd, dev_name); retval = do_move_mount(&path, dev_name);
else 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); dev_name, data_page);
dput_out: dput_out:
path_put(&nd.path); path_put(&path);
return retval; return retval;
} }

View File

@ -707,9 +707,7 @@ static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
{ {
if (NFS_PROTO(dir)->version == 2) if (NFS_PROTO(dir)->version == 2)
return 0; return 0;
if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0) return nd && nfs_lookup_check_intent(nd, LOOKUP_EXCL);
return 0;
return (nd->intent.open.flags & O_EXCL) != 0;
} }
/* /*
@ -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 /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
* the dentry. */ * the dentry. */
if (nd->intent.open.flags & O_EXCL) { if (nd->flags & LOOKUP_EXCL) {
d_instantiate(dentry, NULL); d_instantiate(dentry, NULL);
goto out; goto out;
} }
@ -1959,6 +1957,9 @@ force_lookup:
} else } else
res = PTR_ERR(cred); res = PTR_ERR(cred);
out: out:
if (!res && (mask & MAY_EXEC) && !execute_ok(inode))
res = -EACCES;
dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n", dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n",
inode->i_sb->s_id, inode->i_ino, mask, res); inode->i_sb->s_id, inode->i_ino, mask, res);
return res; return res;

View File

@ -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 * 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 * exists, we'll pick it up at this point and use it as the root
*/ */
mntroot = d_alloc_anon(inode); mntroot = d_obtain_alias(inode);
if (!mntroot) { if (IS_ERR(mntroot)) {
iput(inode);
dprintk("nfs_get_root: get root dentry failed\n"); dprintk("nfs_get_root: get root dentry failed\n");
return ERR_PTR(-ENOMEM); return mntroot;
} }
security_d_instantiate(mntroot, inode); 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 * 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 * exists, we'll pick it up at this point and use it as the root
*/ */
mntroot = d_alloc_anon(inode); mntroot = d_obtain_alias(inode);
if (!mntroot) { if (IS_ERR(mntroot)) {
iput(inode);
dprintk("nfs_get_root: get root dentry failed\n"); dprintk("nfs_get_root: get root dentry failed\n");
return ERR_PTR(-ENOMEM); return mntroot;
} }
security_d_instantiate(mntroot, inode); security_d_instantiate(mntroot, inode);

View File

@ -163,18 +163,16 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
if (!ek) if (!ek)
err = -ENOMEM; err = -ENOMEM;
} else { } else {
struct nameidata nd; err = kern_path(buf, 0, &key.ek_path);
err = path_lookup(buf, 0, &nd);
if (err) if (err)
goto out; goto out;
dprintk("Found the path %s\n", buf); dprintk("Found the path %s\n", buf);
key.ek_path = nd.path;
ek = svc_expkey_update(&key, ek); ek = svc_expkey_update(&key, ek);
if (!ek) if (!ek)
err = -ENOMEM; err = -ENOMEM;
path_put(&nd.path); path_put(&key.ek_path);
} }
cache_flush(); cache_flush();
out: out:
@ -501,35 +499,22 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
int len; int len;
int err; int err;
struct auth_domain *dom = NULL; struct auth_domain *dom = NULL;
struct nameidata nd; struct svc_export exp = {}, *expp;
struct svc_export exp, *expp;
int an_int; 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') if (mesg[mlen-1] != '\n')
return -EINVAL; return -EINVAL;
mesg[mlen-1] = 0; mesg[mlen-1] = 0;
buf = kmalloc(PAGE_SIZE, GFP_KERNEL); buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
err = -ENOMEM; if (!buf)
if (!buf) goto out; return -ENOMEM;
/* client */ /* client */
len = qword_get(&mesg, buf, PAGE_SIZE);
err = -EINVAL; err = -EINVAL;
if (len <= 0) goto out; len = qword_get(&mesg, buf, PAGE_SIZE);
if (len <= 0)
goto out;
err = -ENOENT; err = -ENOENT;
dom = auth_domain_find(buf); dom = auth_domain_find(buf);
@ -538,25 +523,25 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
/* path */ /* path */
err = -EINVAL; err = -EINVAL;
if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
goto out; goto out1;
err = path_lookup(buf, 0, &nd);
if (err) goto out_no_path; err = kern_path(buf, 0, &exp.ex_path);
if (err)
goto out1;
exp.h.flags = 0;
exp.ex_client = dom; 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; err = -ENOMEM;
exp.ex_pathname = kstrdup(buf, GFP_KERNEL);
if (!exp.ex_pathname) if (!exp.ex_pathname)
goto out; goto out2;
/* expiry */ /* expiry */
err = -EINVAL; err = -EINVAL;
exp.h.expiry_time = get_expiry(&mesg); exp.h.expiry_time = get_expiry(&mesg);
if (exp.h.expiry_time == 0) if (exp.h.expiry_time == 0)
goto out; goto out3;
/* flags */ /* flags */
err = get_int(&mesg, &an_int); 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; err = 0;
set_bit(CACHE_NEGATIVE, &exp.h.flags); set_bit(CACHE_NEGATIVE, &exp.h.flags);
} else { } else {
if (err || an_int < 0) goto out; if (err || an_int < 0)
goto out3;
exp.ex_flags= an_int; exp.ex_flags= an_int;
/* anon uid */ /* anon uid */
err = get_int(&mesg, &an_int); err = get_int(&mesg, &an_int);
if (err) goto out; if (err)
goto out3;
exp.ex_anon_uid= an_int; exp.ex_anon_uid= an_int;
/* anon gid */ /* anon gid */
err = get_int(&mesg, &an_int); err = get_int(&mesg, &an_int);
if (err) goto out; if (err)
goto out3;
exp.ex_anon_gid= an_int; exp.ex_anon_gid= an_int;
/* fsid */ /* fsid */
err = get_int(&mesg, &an_int); err = get_int(&mesg, &an_int);
if (err) goto out; if (err)
goto out3;
exp.ex_fsid = an_int; exp.ex_fsid = an_int;
while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) { 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; break;
if (err) 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); exp.ex_uuid);
if (err) goto out; if (err)
goto out4;
} }
expp = svc_export_lookup(&exp); expp = svc_export_lookup(&exp);
@ -623,15 +613,16 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
err = -ENOMEM; err = -ENOMEM;
else else
exp_put(expp); exp_put(expp);
out: out4:
nfsd4_fslocs_free(&exp.ex_fslocs); nfsd4_fslocs_free(&exp.ex_fslocs);
kfree(exp.ex_uuid); kfree(exp.ex_uuid);
out3:
kfree(exp.ex_pathname); kfree(exp.ex_pathname);
if (nd.path.dentry) out2:
path_put(&nd.path); path_put(&exp.ex_path);
out_no_path: out1:
if (dom) auth_domain_put(dom);
auth_domain_put(dom); out:
kfree(buf); kfree(buf);
return err; return err;
} }
@ -999,7 +990,7 @@ exp_export(struct nfsctl_export *nxp)
struct svc_export *exp = NULL; struct svc_export *exp = NULL;
struct svc_export new; struct svc_export new;
struct svc_expkey *fsid_key = NULL; struct svc_expkey *fsid_key = NULL;
struct nameidata nd; struct path path;
int err; int err;
/* Consistency check */ /* Consistency check */
@ -1022,12 +1013,12 @@ exp_export(struct nfsctl_export *nxp)
/* Look up the dentry */ /* Look up the dentry */
err = path_lookup(nxp->ex_path, 0, &nd); err = kern_path(nxp->ex_path, 0, &path);
if (err) if (err)
goto out_put_clp; goto out_put_clp;
err = -EINVAL; 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)); memset(&new, 0, sizeof(new));
@ -1035,8 +1026,8 @@ exp_export(struct nfsctl_export *nxp)
if ((nxp->ex_flags & NFSEXP_FSID) && if ((nxp->ex_flags & NFSEXP_FSID) &&
(!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) && (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
fsid_key->ek_path.mnt && fsid_key->ek_path.mnt &&
(fsid_key->ek_path.mnt != nd.path.mnt || (fsid_key->ek_path.mnt != path.mnt ||
fsid_key->ek_path.dentry != nd.path.dentry)) fsid_key->ek_path.dentry != path.dentry))
goto finish; goto finish;
if (!IS_ERR(exp)) { if (!IS_ERR(exp)) {
@ -1052,7 +1043,7 @@ exp_export(struct nfsctl_export *nxp)
goto finish; 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; if (err) goto finish;
err = -ENOMEM; err = -ENOMEM;
@ -1065,7 +1056,7 @@ exp_export(struct nfsctl_export *nxp)
if (!new.ex_pathname) if (!new.ex_pathname)
goto finish; goto finish;
new.ex_client = clp; new.ex_client = clp;
new.ex_path = nd.path; new.ex_path = path;
new.ex_flags = nxp->ex_flags; new.ex_flags = nxp->ex_flags;
new.ex_anon_uid = nxp->ex_anon_uid; new.ex_anon_uid = nxp->ex_anon_uid;
new.ex_anon_gid = nxp->ex_anon_gid; new.ex_anon_gid = nxp->ex_anon_gid;
@ -1091,7 +1082,7 @@ finish:
exp_put(exp); exp_put(exp);
if (fsid_key && !IS_ERR(fsid_key)) if (fsid_key && !IS_ERR(fsid_key))
cache_put(&fsid_key->h, &svc_expkey_cache); cache_put(&fsid_key->h, &svc_expkey_cache);
path_put(&nd.path); path_put(&path);
out_put_clp: out_put_clp:
auth_domain_put(clp); auth_domain_put(clp);
out_unlock: out_unlock:
@ -1122,7 +1113,7 @@ exp_unexport(struct nfsctl_export *nxp)
{ {
struct auth_domain *dom; struct auth_domain *dom;
svc_export *exp; svc_export *exp;
struct nameidata nd; struct path path;
int err; int err;
/* Consistency check */ /* Consistency check */
@ -1139,13 +1130,13 @@ exp_unexport(struct nfsctl_export *nxp)
goto out_unlock; goto out_unlock;
} }
err = path_lookup(nxp->ex_path, 0, &nd); err = kern_path(nxp->ex_path, 0, &path);
if (err) if (err)
goto out_domain; goto out_domain;
err = -EINVAL; err = -EINVAL;
exp = exp_get_by_name(dom, nd.path.mnt, nd.path.dentry, NULL); exp = exp_get_by_name(dom, path.mnt, path.dentry, NULL);
path_put(&nd.path); path_put(&path);
if (IS_ERR(exp)) if (IS_ERR(exp))
goto out_domain; goto out_domain;
@ -1167,26 +1158,26 @@ out_unlock:
* since its harder to fool a kernel module than a user space program. * since its harder to fool a kernel module than a user space program.
*/ */
int 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 svc_export *exp;
struct nameidata nd; struct path path;
struct inode *inode; struct inode *inode;
struct svc_fh fh; struct svc_fh fh;
int err; int err;
err = -EPERM; err = -EPERM;
/* NB: we probably ought to check that it's NUL-terminated */ /* NB: we probably ought to check that it's NUL-terminated */
if (path_lookup(path, 0, &nd)) { if (kern_path(name, 0, &path)) {
printk("nfsd: exp_rootfh path not found %s", path); printk("nfsd: exp_rootfh path not found %s", name);
return err; return err;
} }
inode = nd.path.dentry->d_inode; inode = path.dentry->d_inode;
dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", 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); 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)) { if (IS_ERR(exp)) {
err = PTR_ERR(exp); err = PTR_ERR(exp);
goto out; 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 must be initialized before calling fh_compose
*/ */
fh_init(&fh, maxsize); fh_init(&fh, maxsize);
if (fh_compose(&fh, exp, nd.path.dentry, NULL)) if (fh_compose(&fh, exp, path.dentry, NULL))
err = -EINVAL; err = -EINVAL;
else else
err = 0; err = 0;
@ -1204,7 +1195,7 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
fh_put(&fh); fh_put(&fh);
exp_put(exp); exp_put(exp);
out: out:
path_put(&nd.path); path_put(&path);
return err; return err;
} }

View File

@ -51,7 +51,7 @@
#define NFSDDBG_FACILITY NFSDDBG_PROC #define NFSDDBG_FACILITY NFSDDBG_PROC
/* Globals */ /* Globals */
static struct nameidata rec_dir; static struct path rec_dir;
static int rec_dir_init = 0; static int rec_dir_init = 0;
static void static void
@ -121,9 +121,9 @@ out_no_tfm:
static void static void
nfsd4_sync_rec_dir(void) nfsd4_sync_rec_dir(void)
{ {
mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex); mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
nfsd_sync_dir(rec_dir.path.dentry); nfsd_sync_dir(rec_dir.dentry);
mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex); mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
} }
int int
@ -143,9 +143,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
nfs4_save_user(&uid, &gid); nfs4_save_user(&uid, &gid);
/* lock the parent */ /* 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)) { if (IS_ERR(dentry)) {
status = PTR_ERR(dentry); status = PTR_ERR(dentry);
goto out_unlock; goto out_unlock;
@ -155,15 +155,15 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n");
goto out_put; goto out_put;
} }
status = mnt_want_write(rec_dir.path.mnt); status = mnt_want_write(rec_dir.mnt);
if (status) if (status)
goto out_put; goto out_put;
status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, S_IRWXU); status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU);
mnt_drop_write(rec_dir.path.mnt); mnt_drop_write(rec_dir.mnt);
out_put: out_put:
dput(dentry); dput(dentry);
out_unlock: out_unlock:
mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex); mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
if (status == 0) { if (status == 0) {
clp->cl_firststate = 1; clp->cl_firststate = 1;
nfsd4_sync_rec_dir(); nfsd4_sync_rec_dir();
@ -226,7 +226,7 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
nfs4_save_user(&uid, &gid); 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); status = PTR_ERR(filp);
if (IS_ERR(filp)) if (IS_ERR(filp))
goto out; 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); dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex); mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
dentry = lookup_one_len(name, rec_dir.path.dentry, namlen); dentry = lookup_one_len(name, rec_dir.dentry, namlen);
mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex); mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
status = PTR_ERR(dentry); status = PTR_ERR(dentry);
return status; return status;
@ -302,7 +302,7 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
if (!dentry->d_inode) if (!dentry->d_inode)
goto out; goto out;
status = nfsd4_clear_clid_dir(rec_dir.path.dentry, dentry); status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry);
out: out:
dput(dentry); dput(dentry);
return status; return status;
@ -318,7 +318,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
if (!rec_dir_init || !clp->cl_firststate) if (!rec_dir_init || !clp->cl_firststate)
return; return;
status = mnt_want_write(rec_dir.path.mnt); status = mnt_want_write(rec_dir.mnt);
if (status) if (status)
goto out; goto out;
clp->cl_firststate = 0; clp->cl_firststate = 0;
@ -327,7 +327,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
nfs4_reset_user(uid, gid); nfs4_reset_user(uid, gid);
if (status == 0) if (status == 0)
nfsd4_sync_rec_dir(); nfsd4_sync_rec_dir();
mnt_drop_write(rec_dir.path.mnt); mnt_drop_write(rec_dir.mnt);
out: out:
if (status) if (status)
printk("NFSD: Failed to remove expired client state directory" printk("NFSD: Failed to remove expired client state directory"
@ -357,17 +357,17 @@ nfsd4_recdir_purge_old(void) {
if (!rec_dir_init) if (!rec_dir_init)
return; return;
status = mnt_want_write(rec_dir.path.mnt); status = mnt_want_write(rec_dir.mnt);
if (status) if (status)
goto out; 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) if (status == 0)
nfsd4_sync_rec_dir(); nfsd4_sync_rec_dir();
mnt_drop_write(rec_dir.path.mnt); mnt_drop_write(rec_dir.mnt);
out: out:
if (status) if (status)
printk("nfsd4: failed to purge old clients from recovery" 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 static int
@ -387,10 +387,10 @@ int
nfsd4_recdir_load(void) { nfsd4_recdir_load(void) {
int status; 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) if (status)
printk("nfsd4: failed loading clients from recovery" 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; return status;
} }
@ -412,7 +412,7 @@ nfsd4_init_recdir(char *rec_dirname)
nfs4_save_user(&uid, &gid); 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); &rec_dir);
if (status) if (status)
printk("NFSD: unable to find recovery directory %s\n", printk("NFSD: unable to find recovery directory %s\n",
@ -429,5 +429,5 @@ nfsd4_shutdown_recdir(void)
if (!rec_dir_init) if (!rec_dir_init)
return; return;
rec_dir_init = 0; rec_dir_init = 0;
path_put(&rec_dir.path); path_put(&rec_dir);
} }

View File

@ -3284,17 +3284,17 @@ int
nfs4_reset_recoverydir(char *recdir) nfs4_reset_recoverydir(char *recdir)
{ {
int status; int status;
struct nameidata nd; struct path path;
status = path_lookup(recdir, LOOKUP_FOLLOW, &nd); status = kern_path(recdir, LOOKUP_FOLLOW, &path);
if (status) if (status)
return status; return status;
status = -ENOTDIR; 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); nfs4_set_recdir(recdir);
status = 0; status = 0;
} }
path_put(&nd.path); path_put(&path);
return status; return status;
} }

View File

@ -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) static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size)
{ {
struct nameidata nd; struct path path;
char *fo_path; char *fo_path;
int error; 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) if (qword_get(&buf, fo_path, size) < 0)
return -EINVAL; return -EINVAL;
error = path_lookup(fo_path, 0, &nd); error = kern_path(fo_path, 0, &path);
if (error) if (error)
return 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; return error;
} }

View File

@ -1817,6 +1817,115 @@ out:
return err; 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. * Read entries from a directory.
* The NFSv3/4 verifier we ignore for now. * 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) struct readdir_cd *cdp, filldir_t func)
{ {
__be32 err; __be32 err;
int host_err;
struct file *file; struct file *file;
loff_t offset = *offsetp; loff_t offset = *offsetp;
@ -1840,21 +1948,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
goto out_close; goto out_close;
} }
/* err = nfsd_buffered_readdir(file, func, cdp, offsetp);
* 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);
if (err == nfserr_eof || err == nfserr_toosmall) if (err == nfserr_eof || err == nfserr_toosmall)
err = nfs_ok; /* can still be found in ->err */ err = nfs_ok; /* can still be found in ->err */

View File

@ -304,8 +304,6 @@ static struct dentry *ntfs_get_parent(struct dentry *child_dent)
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
ATTR_RECORD *attr; ATTR_RECORD *attr;
FILE_NAME_ATTR *fn; FILE_NAME_ATTR *fn;
struct inode *parent_vi;
struct dentry *parent_dent;
unsigned long parent_ino; unsigned long parent_ino;
int err; int err;
@ -345,24 +343,8 @@ try_next:
/* Release the search context and the mft record of the child. */ /* Release the search context and the mft record of the child. */
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
unmap_mft_record(ni); unmap_mft_record(ni);
/* Get the inode of the parent directory. */
parent_vi = ntfs_iget(vi->i_sb, parent_ino); return d_obtain_alias(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;
} }
static struct inode *ntfs_nfs_get_inode(struct super_block *sb, static struct inode *ntfs_nfs_get_inode(struct super_block *sb,

View File

@ -68,14 +68,9 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb,
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
} }
result = d_alloc_anon(inode); result = d_obtain_alias(inode);
if (!IS_ERR(result))
if (!result) { result->d_op = &ocfs2_dentry_ops;
iput(inode);
mlog_errno(-ENOMEM);
return ERR_PTR(-ENOMEM);
}
result->d_op = &ocfs2_dentry_ops;
mlog_exit_ptr(result); mlog_exit_ptr(result);
return result; return result;
@ -86,7 +81,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
int status; int status;
u64 blkno; u64 blkno;
struct dentry *parent; struct dentry *parent;
struct inode *inode;
struct inode *dir = child->d_inode; struct inode *dir = child->d_inode;
mlog_entry("(0x%p, '%.*s')\n", child, mlog_entry("(0x%p, '%.*s')\n", child,
@ -109,21 +103,9 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
goto bail_unlock; goto bail_unlock;
} }
inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0); parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
if (IS_ERR(inode)) { if (!IS_ERR(parent))
mlog(ML_ERROR, "Unable to create inode %llu\n", parent->d_op = &ocfs2_dentry_ops;
(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;
bail_unlock: bail_unlock:
ocfs2_inode_unlock(dir, 0); ocfs2_inode_unlock(dir, 0);

View File

@ -501,4 +501,5 @@ struct inode_operations omfs_dir_inops = {
struct file_operations omfs_dir_operations = { struct file_operations omfs_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = omfs_readdir, .readdir = omfs_readdir,
.llseek = generic_file_llseek,
}; };

View File

@ -167,6 +167,7 @@ static int openpromfs_readdir(struct file *, void *, filldir_t);
static const struct file_operations openprom_operations = { static const struct file_operations openprom_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = openpromfs_readdir, .readdir = openpromfs_readdir,
.llseek = generic_file_llseek,
}; };
static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *); static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *);

View File

@ -298,13 +298,19 @@ static int proc_sys_permission(struct inode *inode, int mask)
* sysctl entries that are not writeable, * sysctl entries that are not writeable,
* are _NOT_ writeable, capabilities or not. * are _NOT_ writeable, capabilities or not.
*/ */
struct ctl_table_header *head = grab_header(inode); struct ctl_table_header *head;
struct ctl_table *table = PROC_I(inode)->sysctl_entry; struct ctl_table *table;
int error; 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)) if (IS_ERR(head))
return PTR_ERR(head); return PTR_ERR(head);
table = PROC_I(inode)->sysctl_entry;
if (!table) /* global root - r-xr-xr-x */ if (!table) /* global root - r-xr-xr-x */
error = mask & MAY_WRITE ? -EACCES : 0; error = mask & MAY_WRITE ? -EACCES : 0;
else /* Use the permissions on the sysctl table entry */ 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 = { static const struct file_operations proc_sys_dir_file_operations = {
.readdir = proc_sys_readdir, .readdir = proc_sys_readdir,
.llseek = generic_file_llseek,
}; };
static const struct inode_operations proc_sys_inode_operations = { static const struct inode_operations proc_sys_inode_operations = {

View File

@ -31,39 +31,61 @@ const struct file_operations generic_ro_fops = {
EXPORT_SYMBOL(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 loff_t
generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
{ {
loff_t retval;
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
switch (origin) { switch (origin) {
case SEEK_END: case SEEK_END:
offset += inode->i_size; offset += inode->i_size;
break; break;
case SEEK_CUR: case SEEK_CUR:
offset += file->f_pos; offset += file->f_pos;
break;
} }
retval = -EINVAL;
if (offset>=0 && offset<=inode->i_sb->s_maxbytes) { if (offset < 0 || offset > inode->i_sb->s_maxbytes)
/* Special lock needed here? */ return -EINVAL;
if (offset != file->f_pos) {
file->f_pos = offset; /* Special lock needed here? */
file->f_version = 0; if (offset != file->f_pos) {
} file->f_pos = offset;
retval = offset; file->f_version = 0;
} }
return retval;
return offset;
} }
EXPORT_SYMBOL(generic_file_llseek_unlocked); 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 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); 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); mutex_unlock(&file->f_dentry->d_inode->i_mutex);
return n;
return rval;
} }
EXPORT_SYMBOL(generic_file_llseek); EXPORT_SYMBOL(generic_file_llseek);

View File

@ -117,7 +117,7 @@ asmlinkage long old_readdir(unsigned int fd, struct old_linux_dirent __user * di
buf.dirent = dirent; buf.dirent = dirent;
error = vfs_readdir(file, fillonedir, &buf); error = vfs_readdir(file, fillonedir, &buf);
if (error >= 0) if (buf.result)
error = buf.result; error = buf.result;
fput(file); fput(file);
@ -209,9 +209,8 @@ asmlinkage long sys_getdents(unsigned int fd, struct linux_dirent __user * diren
buf.error = 0; buf.error = 0;
error = vfs_readdir(file, filldir, &buf); error = vfs_readdir(file, filldir, &buf);
if (error < 0) if (error >= 0)
goto out_putf; error = buf.error;
error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;
if (lastdirent) { if (lastdirent) {
if (put_user(file->f_pos, &lastdirent->d_off)) 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 else
error = count - buf.count; error = count - buf.count;
} }
out_putf:
fput(file); fput(file);
out: out:
return error; return error;
@ -293,19 +290,16 @@ asmlinkage long sys_getdents64(unsigned int fd, struct linux_dirent64 __user * d
buf.error = 0; buf.error = 0;
error = vfs_readdir(file, filldir64, &buf); error = vfs_readdir(file, filldir64, &buf);
if (error < 0) if (error >= 0)
goto out_putf; error = buf.error;
error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;
if (lastdirent) { if (lastdirent) {
typeof(lastdirent->d_off) d_off = file->f_pos; typeof(lastdirent->d_off) d_off = file->f_pos;
error = -EFAULT;
if (__put_user(d_off, &lastdirent->d_off)) if (__put_user(d_off, &lastdirent->d_off))
goto out_putf; error = -EFAULT;
error = count - buf.count; else
error = count - buf.count;
} }
out_putf:
fput(file); fput(file);
out: out:
return error; return error;

View File

@ -296,6 +296,7 @@ const struct file_operations reiserfs_file_operations = {
.aio_write = generic_file_aio_write, .aio_write = generic_file_aio_write,
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write, .splice_write = generic_file_splice_write,
.llseek = generic_file_llseek,
}; };
const struct inode_operations reiserfs_file_inode_operations = { const struct inode_operations reiserfs_file_inode_operations = {

View File

@ -1522,7 +1522,6 @@ static struct dentry *reiserfs_get_dentry(struct super_block *sb,
{ {
struct cpu_key key; struct cpu_key key;
struct dentry *result;
struct inode *inode; struct inode *inode;
key.on_disk_key.k_objectid = objectid; key.on_disk_key.k_objectid = objectid;
@ -1535,16 +1534,8 @@ static struct dentry *reiserfs_get_dentry(struct super_block *sb,
inode = NULL; inode = NULL;
} }
reiserfs_write_unlock(sb); reiserfs_write_unlock(sb);
if (!inode)
inode = ERR_PTR(-ESTALE); return d_obtain_alias(inode);
if (IS_ERR(inode))
return ERR_CAST(inode);
result = d_alloc_anon(inode);
if (!result) {
iput(inode);
return ERR_PTR(-ENOMEM);
}
return result;
} }
struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid, struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,

View File

@ -383,7 +383,6 @@ struct dentry *reiserfs_get_parent(struct dentry *child)
struct inode *inode = NULL; struct inode *inode = NULL;
struct reiserfs_dir_entry de; struct reiserfs_dir_entry de;
INITIALIZE_PATH(path_to_entry); INITIALIZE_PATH(path_to_entry);
struct dentry *parent;
struct inode *dir = child->d_inode; struct inode *dir = child->d_inode;
if (dir->i_nlink == 0) { 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)); inode = reiserfs_iget(dir->i_sb, (struct cpu_key *)&(de.de_dir_id));
reiserfs_write_unlock(dir->i_sb); reiserfs_write_unlock(dir->i_sb);
if (!inode || IS_ERR(inode)) { return d_obtain_alias(inode);
return ERR_PTR(-EACCES);
}
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
parent = ERR_PTR(-ENOMEM);
}
return parent;
} }
/* add entry to the directory (entry can be hidden). /* add entry to the directory (entry can be hidden).

View File

@ -2058,10 +2058,10 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on * Standard function to be called on quota_on
*/ */
static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
char *path, int remount) char *name, int remount)
{ {
int err; int err;
struct nameidata nd; struct path path;
struct inode *inode; struct inode *inode;
struct reiserfs_transaction_handle th; 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; return -EINVAL;
/* No more checks needed? Path and format_id are bogus anyway... */ /* No more checks needed? Path and format_id are bogus anyway... */
if (remount) if (remount)
return vfs_quota_on(sb, type, format_id, path, 1); return vfs_quota_on(sb, type, format_id, name, 1);
err = path_lookup(path, LOOKUP_FOLLOW, &nd); err = kern_path(name, LOOKUP_FOLLOW, &path);
if (err) if (err)
return err; return err;
/* Quotafile not on the same filesystem? */ /* Quotafile not on the same filesystem? */
if (nd.path.mnt->mnt_sb != sb) { if (path.mnt->mnt_sb != sb) {
err = -EXDEV; err = -EXDEV;
goto out; 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 */ /* We must not pack tails for quota files on reiserfs for quota IO to work */
if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) { if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {
err = reiserfs_unpack(inode, NULL); 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? */ /* Journaling quota? */
if (REISERFS_SB(sb)->s_qf_names[type]) { if (REISERFS_SB(sb)->s_qf_names[type]) {
/* Quotafile not of fs root? */ /* 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_warning(sb,
"reiserfs: Quota file not on filesystem root. " "reiserfs: Quota file not on filesystem root. "
"Journalled quota will not work."); "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) if (err)
goto out; goto out;
} }
err = vfs_quota_on_path(sb, type, format_id, &nd.path); err = vfs_quota_on_path(sb, type, format_id, &path);
out: out:
path_put(&nd.path); path_put(&path);
return err; return err;
} }

View File

@ -682,7 +682,7 @@ void emergency_remount(void)
* filesystems which don't use real block-devices. -- jrs * 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 */ static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */
int set_anon_super(struct super_block *s, void *data) 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; int error;
retry: retry:
if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0) if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)
return -ENOMEM; return -ENOMEM;
spin_lock(&unnamed_dev_lock); 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); spin_unlock(&unnamed_dev_lock);
if (error == -EAGAIN) if (error == -EAGAIN)
/* We raced and lost with another CPU. */ /* 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)) { if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
spin_lock(&unnamed_dev_lock); spin_lock(&unnamed_dev_lock);
idr_remove(&unnamed_dev_idr, dev); ida_remove(&unnamed_dev_ida, dev);
spin_unlock(&unnamed_dev_lock); spin_unlock(&unnamed_dev_lock);
return -EMFILE; return -EMFILE;
} }
@ -720,17 +720,12 @@ void kill_anon_super(struct super_block *sb)
generic_shutdown_super(sb); generic_shutdown_super(sb);
spin_lock(&unnamed_dev_lock); spin_lock(&unnamed_dev_lock);
idr_remove(&unnamed_dev_idr, slot); ida_remove(&unnamed_dev_ida, slot);
spin_unlock(&unnamed_dev_lock); spin_unlock(&unnamed_dev_lock);
} }
EXPORT_SYMBOL(kill_anon_super); EXPORT_SYMBOL(kill_anon_super);
void __init unnamed_dev_init(void)
{
idr_init(&unnamed_dev_idr);
}
void kill_litter_super(struct super_block *sb) void kill_litter_super(struct super_block *sb)
{ {
if (sb->s_root) if (sb->s_root)

View File

@ -983,4 +983,5 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
const struct file_operations sysfs_dir_operations = { const struct file_operations sysfs_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = sysfs_readdir, .readdir = sysfs_readdir,
.llseek = generic_file_llseek,
}; };

View File

@ -142,7 +142,7 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
} }
static struct fileIdentDesc *udf_find_entry(struct inode *dir, static struct fileIdentDesc *udf_find_entry(struct inode *dir,
struct dentry *dentry, struct qstr *child,
struct udf_fileident_bh *fibh, struct udf_fileident_bh *fibh,
struct fileIdentDesc *cfi) struct fileIdentDesc *cfi)
{ {
@ -159,8 +159,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
sector_t offset; sector_t offset;
struct extent_position epos = {}; struct extent_position epos = {};
struct udf_inode_info *dinfo = UDF_I(dir); struct udf_inode_info *dinfo = UDF_I(dir);
int isdotdot = dentry->d_name.len == 2 && int isdotdot = child->len == 2 &&
dentry->d_name.name[0] == '.' && dentry->d_name.name[1] == '.'; child->name[0] == '.' && child->name[1] == '.';
size = udf_ext0_offset(dir) + dir->i_size; size = udf_ext0_offset(dir) + dir->i_size;
f_pos = udf_ext0_offset(dir); f_pos = udf_ext0_offset(dir);
@ -238,8 +238,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
continue; continue;
flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
if (flen && udf_match(flen, fname, dentry->d_name.len, if (flen && udf_match(flen, fname, child->len, child->name))
dentry->d_name.name))
goto out_ok; goto out_ok;
} }
@ -283,7 +282,7 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
} else } else
#endif /* UDF_RECOVERY */ #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) if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh); brelse(fibh.ebh);
brelse(fibh.sbh); brelse(fibh.sbh);
@ -783,7 +782,7 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
retval = -ENOENT; retval = -ENOENT;
lock_kernel(); lock_kernel();
fi = udf_find_entry(dir, dentry, &fibh, &cfi); fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
if (!fi) if (!fi)
goto out; goto out;
@ -829,7 +828,7 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)
retval = -ENOENT; retval = -ENOENT;
lock_kernel(); lock_kernel();
fi = udf_find_entry(dir, dentry, &fibh, &cfi); fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
if (!fi) if (!fi)
goto out; 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); struct udf_inode_info *old_iinfo = UDF_I(old_inode);
lock_kernel(); 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 (ofi) {
if (ofibh.sbh != ofibh.ebh) if (ofibh.sbh != ofibh.ebh)
brelse(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) != old_inode->i_ino)
goto end_rename; 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 (nfi) {
if (!new_inode) { if (!new_inode) {
if (nfibh.sbh != nfibh.ebh) 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); udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);
/* The old fid may have moved - find it again */ /* 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); udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
if (new_inode) { if (new_inode) {
@ -1243,15 +1242,11 @@ end_rename:
static struct dentry *udf_get_parent(struct dentry *child) static struct dentry *udf_get_parent(struct dentry *child)
{ {
struct dentry *parent;
struct inode *inode = NULL; struct inode *inode = NULL;
struct dentry dotdot; struct qstr dotdot = {.name = "..", .len = 2};
struct fileIdentDesc cfi; struct fileIdentDesc cfi;
struct udf_fileident_bh fibh; struct udf_fileident_bh fibh;
dotdot.d_name.name = "..";
dotdot.d_name.len = 2;
lock_kernel(); lock_kernel();
if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi)) if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi))
goto out_unlock; goto out_unlock;
@ -1266,13 +1261,7 @@ static struct dentry *udf_get_parent(struct dentry *child)
goto out_unlock; goto out_unlock;
unlock_kernel(); unlock_kernel();
parent = d_alloc_anon(inode); return d_obtain_alias(inode);
if (!parent) {
iput(inode);
parent = ERR_PTR(-ENOMEM);
}
return parent;
out_unlock: out_unlock:
unlock_kernel(); unlock_kernel();
return ERR_PTR(-EACCES); 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) u16 partref, __u32 generation)
{ {
struct inode *inode; struct inode *inode;
struct dentry *result;
kernel_lb_addr loc; kernel_lb_addr loc;
if (block == 0) if (block == 0)
@ -1300,12 +1288,7 @@ static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
iput(inode); iput(inode);
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
} }
result = d_alloc_anon(inode); return d_obtain_alias(inode);
if (!result) {
iput(inode);
return ERR_PTR(-ENOMEM);
}
return result;
} }
static struct dentry *udf_fh_to_dentry(struct super_block *sb, static struct dentry *udf_fh_to_dentry(struct super_block *sb,

View File

@ -667,4 +667,5 @@ const struct file_operations ufs_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = ufs_readdir, .readdir = ufs_readdir,
.fsync = file_fsync, .fsync = file_fsync,
.llseek = generic_file_llseek,
}; };

View File

@ -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 xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;
struct inode *inode = NULL; struct inode *inode = NULL;
struct dentry *result;
if (fh_len < xfs_fileid_length(fileid_type)) if (fh_len < xfs_fileid_length(fileid_type))
return NULL; return NULL;
@ -164,16 +163,7 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
break; break;
} }
if (!inode) return d_obtain_alias(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;
} }
STATIC struct dentry * 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 xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;
struct inode *inode = NULL; struct inode *inode = NULL;
struct dentry *result;
switch (fileid_type) { switch (fileid_type) {
case FILEID_INO32_GEN_PARENT: case FILEID_INO32_GEN_PARENT:
@ -195,16 +184,7 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
break; break;
} }
if (!inode) return d_obtain_alias(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;
} }
STATIC struct dentry * STATIC struct dentry *
@ -213,18 +193,12 @@ xfs_fs_get_parent(
{ {
int error; int error;
struct xfs_inode *cip; struct xfs_inode *cip;
struct dentry *parent;
error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL); error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL);
if (unlikely(error)) if (unlikely(error))
return ERR_PTR(-error); return ERR_PTR(-error);
parent = d_alloc_anon(VFS_I(cip)); return d_obtain_alias(VFS_I(cip));
if (unlikely(!parent)) {
iput(VFS_I(cip));
return ERR_PTR(-ENOMEM);
}
return parent;
} }
const struct export_operations xfs_export_operations = { const struct export_operations xfs_export_operations = {

View File

@ -204,15 +204,6 @@ xfs_file_fsync(
return -xfs_fsync(XFS_I(dentry->d_inode)); 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 STATIC int
xfs_file_readdir( xfs_file_readdir(
struct file *filp, struct file *filp,
@ -244,125 +235,6 @@ xfs_file_readdir(
return -error; return -error;
return 0; 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 STATIC int
xfs_file_mmap( xfs_file_mmap(

View File

@ -311,11 +311,10 @@ xfs_open_by_handle(
return new_fd; return new_fd;
} }
dentry = d_alloc_anon(inode); dentry = d_obtain_alias(inode);
if (dentry == NULL) { if (IS_ERR(dentry)) {
iput(inode);
put_unused_fd(new_fd); put_unused_fd(new_fd);
return -XFS_ERROR(ENOMEM); return PTR_ERR(dentry);
} }
/* Ensure umount returns EBUSY on umounts while this file is open. */ /* Ensure umount returns EBUSY on umounts while this file is open. */

View File

@ -228,9 +228,9 @@ extern void d_delete(struct dentry *);
/* allocate/de-allocate */ /* allocate/de-allocate */
extern struct dentry * d_alloc(struct dentry *, const struct qstr *); 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_splice_alias(struct inode *, struct dentry *);
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *); 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_sb(struct super_block *);
extern void shrink_dcache_parent(struct dentry *); extern void shrink_dcache_parent(struct dentry *);
extern void shrink_dcache_for_umount(struct super_block *); 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 */ /* used for rename() and baskets */
extern void d_move(struct dentry *, struct dentry *); 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 */ /* appendix may either be NULL or be used for transname suffixes */
extern struct dentry * d_lookup(struct dentry *, struct qstr *); extern struct dentry * d_lookup(struct dentry *, struct qstr *);

View File

@ -136,7 +136,7 @@ extern int dir_notify_enable;
/* /*
* Superblock flags that can be altered by MS_REMOUNT * 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 * Old magic mount flag and mask
@ -1593,7 +1593,6 @@ extern int get_sb_pseudo(struct file_system_type *, char *,
struct vfsmount *mnt); struct vfsmount *mnt);
extern int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb); extern int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
int __put_super_and_need_restart(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 */ /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
#define fops_get(fops) \ #define fops_get(fops) \
@ -1852,6 +1851,11 @@ extern int inode_permission(struct inode *, int);
extern int generic_permission(struct inode *, int, extern int generic_permission(struct inode *, int,
int (*check_acl)(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 get_write_access(struct inode *);
extern int deny_write_access(struct file *); extern int deny_write_access(struct file *);
static inline void put_write_access(struct inode * inode) static inline void put_write_access(struct inode * inode)

View File

@ -51,8 +51,10 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
/* /*
* Intent data * Intent data
*/ */
#define LOOKUP_OPEN (0x0100) #define LOOKUP_OPEN 0x0100
#define LOOKUP_CREATE (0x0200) #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 *); 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) \ #define user_path_dir(name, path) \
user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, 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 path_lookup(const char *, unsigned, struct nameidata *);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *, extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
const char *, unsigned int, struct nameidata *); const char *, unsigned int, struct nameidata *);

View File

@ -672,7 +672,6 @@ asmlinkage void __init start_kernel(void)
fork_init(num_physpages); fork_init(num_physpages);
proc_caches_init(); proc_caches_init();
buffer_init(); buffer_init();
unnamed_dev_init();
key_init(); key_init();
security_init(); security_init();
vfs_caches_init(num_physpages); vfs_caches_init(num_physpages);

View File

@ -532,7 +532,7 @@ void audit_trim_trees(void)
list_add(&cursor, &tree_list); list_add(&cursor, &tree_list);
while (cursor.next != &tree_list) { while (cursor.next != &tree_list) {
struct audit_tree *tree; struct audit_tree *tree;
struct nameidata nd; struct path path;
struct vfsmount *root_mnt; struct vfsmount *root_mnt;
struct node *node; struct node *node;
struct list_head list; struct list_head list;
@ -544,12 +544,12 @@ void audit_trim_trees(void)
list_add(&cursor, &tree->list); list_add(&cursor, &tree->list);
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
err = path_lookup(tree->pathname, 0, &nd); err = kern_path(tree->pathname, 0, &path);
if (err) if (err)
goto skip_it; goto skip_it;
root_mnt = collect_mounts(nd.path.mnt, nd.path.dentry); root_mnt = collect_mounts(path.mnt, path.dentry);
path_put(&nd.path); path_put(&path);
if (!root_mnt) if (!root_mnt)
goto skip_it; goto skip_it;
@ -580,19 +580,19 @@ skip_it:
} }
static int is_under(struct vfsmount *mnt, struct dentry *dentry, 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 (;;) { for (;;) {
if (mnt->mnt_parent == mnt) if (mnt->mnt_parent == mnt)
return 0; return 0;
if (mnt->mnt_parent == nd->path.mnt) if (mnt->mnt_parent == path->mnt)
break; break;
mnt = mnt->mnt_parent; mnt = mnt->mnt_parent;
} }
dentry = mnt->mnt_mountpoint; 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) 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) int audit_add_tree_rule(struct audit_krule *rule)
{ {
struct audit_tree *seed = rule->tree, *tree; struct audit_tree *seed = rule->tree, *tree;
struct nameidata nd; struct path path;
struct vfsmount *mnt, *p; struct vfsmount *mnt, *p;
struct list_head list; struct list_head list;
int err; int err;
@ -637,11 +637,11 @@ int audit_add_tree_rule(struct audit_krule *rule)
/* do not set rule->tree yet */ /* do not set rule->tree yet */
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
err = path_lookup(tree->pathname, 0, &nd); err = kern_path(tree->pathname, 0, &path);
if (err) if (err)
goto Err; goto Err;
mnt = collect_mounts(nd.path.mnt, nd.path.dentry); mnt = collect_mounts(path.mnt, path.dentry);
path_put(&nd.path); path_put(&path);
if (!mnt) { if (!mnt) {
err = -ENOMEM; err = -ENOMEM;
goto Err; goto Err;
@ -690,29 +690,29 @@ int audit_tag_tree(char *old, char *new)
{ {
struct list_head cursor, barrier; struct list_head cursor, barrier;
int failed = 0; int failed = 0;
struct nameidata nd; struct path path;
struct vfsmount *tagged; struct vfsmount *tagged;
struct list_head list; struct list_head list;
struct vfsmount *mnt; struct vfsmount *mnt;
struct dentry *dentry; struct dentry *dentry;
int err; int err;
err = path_lookup(new, 0, &nd); err = kern_path(new, 0, &path);
if (err) if (err)
return err; return err;
tagged = collect_mounts(nd.path.mnt, nd.path.dentry); tagged = collect_mounts(path.mnt, path.dentry);
path_put(&nd.path); path_put(&path);
if (!tagged) if (!tagged)
return -ENOMEM; return -ENOMEM;
err = path_lookup(old, 0, &nd); err = kern_path(old, 0, &path);
if (err) { if (err) {
drop_collected_mounts(tagged); drop_collected_mounts(tagged);
return err; return err;
} }
mnt = mntget(nd.path.mnt); mnt = mntget(path.mnt);
dentry = dget(nd.path.dentry); dentry = dget(path.dentry);
path_put(&nd.path); path_put(&path);
if (dentry == tagged->mnt_root && dentry == mnt->mnt_root) if (dentry == tagged->mnt_root && dentry == mnt->mnt_root)
follow_up(&mnt, &dentry); follow_up(&mnt, &dentry);
@ -733,7 +733,7 @@ int audit_tag_tree(char *old, char *new)
list_add(&cursor, &tree->list); list_add(&cursor, &tree->list);
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
err = path_lookup(tree->pathname, 0, &nd); err = kern_path(tree->pathname, 0, &path);
if (err) { if (err) {
put_tree(tree); put_tree(tree);
mutex_lock(&audit_filter_mutex); mutex_lock(&audit_filter_mutex);
@ -741,15 +741,15 @@ int audit_tag_tree(char *old, char *new)
} }
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
if (!is_under(mnt, dentry, &nd)) { if (!is_under(mnt, dentry, &path)) {
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
path_put(&nd.path); path_put(&path);
put_tree(tree); put_tree(tree);
mutex_lock(&audit_filter_mutex); mutex_lock(&audit_filter_mutex);
continue; continue;
} }
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
path_put(&nd.path); path_put(&path);
list_for_each_entry(p, &list, mnt_list) { list_for_each_entry(p, &list, mnt_list) {
failed = tag_chunk(p->mnt_root->d_inode, tree); failed = tag_chunk(p->mnt_root->d_inode, tree);

View File

@ -711,28 +711,30 @@ static struct sock *unix_find_other(struct net *net,
int type, unsigned hash, int *error) int type, unsigned hash, int *error)
{ {
struct sock *u; struct sock *u;
struct nameidata nd; struct path path;
int err = 0; int err = 0;
if (sunname->sun_path[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) if (err)
goto fail; goto fail;
err = vfs_permission(&nd, MAY_WRITE); inode = path.dentry->d_inode;
err = inode_permission(inode, MAY_WRITE);
if (err) if (err)
goto put_fail; goto put_fail;
err = -ECONNREFUSED; err = -ECONNREFUSED;
if (!S_ISSOCK(nd.path.dentry->d_inode->i_mode)) if (!S_ISSOCK(inode->i_mode))
goto put_fail; goto put_fail;
u = unix_find_socket_byinode(net, nd.path.dentry->d_inode); u = unix_find_socket_byinode(net, inode);
if (!u) if (!u)
goto put_fail; goto put_fail;
if (u->sk_type == type) 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; err=-EPROTOTYPE;
if (u->sk_type != type) { if (u->sk_type != type) {
@ -753,7 +755,7 @@ static struct sock *unix_find_other(struct net *net,
return u; return u;
put_fail: put_fail:
path_put(&nd.path); path_put(&path);
fail: fail:
*error=err; *error=err;
return NULL; return NULL;