Commit 5b51a7e9 authored by Linus Torvalds's avatar Linus Torvalds

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:
  [PATCH] deal with the first call of ->show() generating no output
  [PATCH] fix ->llseek() for a bunch of directories
  [PATCH] fix regular readdir() and friends
  [PATCH] fix hpux_getdents()
  [PATCH] fix osf_getdirents()
  [PATCH] ntfs: use d_add_ci
  [PATCH] change d_add_ci argument ordering
  [PATCH] fix efs_lookup()
  [PATCH] proc: inode number fixlet
parents 3d87ff3e 4cdfe84b
......@@ -121,24 +121,29 @@ osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
if (reclen > buf->count)
return -EINVAL;
d_ino = ino;
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
buf->error = -EOVERFLOW;
return -EOVERFLOW;
}
if (buf->basep) {
if (put_user(offset, buf->basep))
return -EFAULT;
goto Efault;
buf->basep = NULL;
}
dirent = buf->dirent;
put_user(d_ino, &dirent->d_ino);
put_user(namlen, &dirent->d_namlen);
put_user(reclen, &dirent->d_reclen);
if (copy_to_user(dirent->d_name, name, namlen) ||
if (put_user(d_ino, &dirent->d_ino) ||
put_user(namlen, &dirent->d_namlen) ||
put_user(reclen, &dirent->d_reclen) ||
copy_to_user(dirent->d_name, name, namlen) ||
put_user(0, dirent->d_name + namlen))
return -EFAULT;
goto Efault;
dirent = (void __user *)dirent + reclen;
buf->dirent = dirent;
buf->count -= reclen;
return 0;
Efault:
buf->error = -EFAULT;
return -EFAULT;
}
asmlinkage int
......
......@@ -84,22 +84,28 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
if (reclen > buf->count)
return -EINVAL;
d_ino = ino;
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
buf->error = -EOVERFLOW;
return -EOVERFLOW;
}
dirent = buf->previous;
if (dirent)
put_user(offset, &dirent->d_off);
if (put_user(offset, &dirent->d_off))
goto Efault;
dirent = buf->current_dir;
if (put_user(d_ino, &dirent->d_ino) ||
put_user(reclen, &dirent->d_reclen) ||
put_user(namlen, &dirent->d_namlen) ||
copy_to_user(dirent->d_name, name, namlen) ||
put_user(0, dirent->d_name + namlen))
goto Efault;
buf->previous = dirent;
put_user(d_ino, &dirent->d_ino);
put_user(reclen, &dirent->d_reclen);
put_user(namlen, &dirent->d_namlen);
copy_to_user(dirent->d_name, name, namlen);
put_user(0, dirent->d_name + namlen);
dirent = (void __user *)dirent + reclen;
buf->current_dir = dirent;
buf->current_dir = (void __user *)dirent + reclen;
buf->count -= reclen;
return 0;
Efault:
buffer->error = -EFAULT;
return -EFAULT;
}
#undef NAME_OFFSET
......@@ -126,8 +132,10 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
error = buf.error;
lastdirent = buf.previous;
if (lastdirent) {
put_user(file->f_pos, &lastdirent->d_off);
error = count - buf.count;
if (put_user(file->f_pos, &lastdirent->d_off))
error = -EFAULT;
else
error = count - buf.count;
}
out_putf:
......
......@@ -119,6 +119,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
const struct file_operations v9fs_dir_operations = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = v9fs_dir_readdir,
.open = v9fs_file_open,
.release = v9fs_dir_release,
......
......@@ -197,6 +197,7 @@ adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_inf
const struct file_operations adfs_dir_operations = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = adfs_readdir,
.fsync = file_fsync,
};
......
......@@ -19,6 +19,7 @@ static int affs_readdir(struct file *, void *, filldir_t);
const struct file_operations affs_dir_operations = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = affs_readdir,
.fsync = file_fsync,
};
......
......@@ -36,6 +36,7 @@ const struct file_operations autofs4_root_operations = {
.release = dcache_dir_close,
.read = generic_read_dir,
.readdir = dcache_readdir,
.llseek = dcache_dir_lseek,
.ioctl = autofs4_root_ioctl,
};
......@@ -44,6 +45,7 @@ const struct file_operations autofs4_dir_operations = {
.release = dcache_dir_close,
.read = generic_read_dir,
.readdir = dcache_readdir,
.llseek = dcache_dir_lseek,
};
const struct inode_operations autofs4_indirect_root_inode_operations = {
......
......@@ -66,6 +66,7 @@ static struct kmem_cache *befs_inode_cachep;
static const struct file_operations befs_dir_operations = {
.read = generic_read_dir,
.readdir = befs_readdir,
.llseek = generic_file_llseek,
};
static const struct inode_operations befs_dir_inode_operations = {
......
......@@ -792,8 +792,10 @@ static int compat_fillonedir(void *__buf, const char *name, int namlen,
if (buf->result)
return -EINVAL;
d_ino = ino;
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
buf->result = -EOVERFLOW;
return -EOVERFLOW;
}
buf->result++;
dirent = buf->dirent;
if (!access_ok(VERIFY_WRITE, dirent,
......@@ -862,8 +864,10 @@ static int compat_filldir(void *__buf, const char *name, int namlen,
if (reclen > buf->count)
return -EINVAL;
d_ino = ino;
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
buf->error = -EOVERFLOW;
return -EOVERFLOW;
}
dirent = buf->previous;
if (dirent) {
if (__put_user(offset, &dirent->d_off))
......
......@@ -1236,7 +1236,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
* If no entry exists with the exact case name, allocate new dentry with
* the exact case, and return the spliced entry.
*/
struct dentry *d_add_ci(struct inode *inode, struct dentry *dentry,
struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
struct qstr *name)
{
int error;
......
......@@ -74,8 +74,7 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
}
unlock_kernel();
d_add(dentry, inode);
return NULL;
return d_splice_alias(inode, dentry);
}
static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino,
......
......@@ -174,7 +174,6 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
// TODO: Consider moving this lot to a separate function! (AIA)
handle_name:
{
struct dentry *real_dent, *new_dent;
MFT_RECORD *m;
ntfs_attr_search_ctx *ctx;
ntfs_inode *ni = NTFS_I(dent_inode);
......@@ -255,93 +254,9 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
}
nls_name.hash = full_name_hash(nls_name.name, nls_name.len);
/*
* Note: No need for dent->d_lock lock as i_mutex is held on the
* parent inode.
*/
/* Does a dentry matching the nls_name exist already? */
real_dent = d_lookup(dent->d_parent, &nls_name);
/* If not, create it now. */
if (!real_dent) {
real_dent = d_alloc(dent->d_parent, &nls_name);
kfree(nls_name.name);
if (!real_dent) {
err = -ENOMEM;
goto err_out;
}
new_dent = d_splice_alias(dent_inode, real_dent);
if (new_dent)
dput(real_dent);
else
new_dent = real_dent;
ntfs_debug("Done. (Created new dentry.)");
return new_dent;
}
dent = d_add_ci(dent, dent_inode, &nls_name);
kfree(nls_name.name);
/* Matching dentry exists, check if it is negative. */
if (real_dent->d_inode) {
if (unlikely(real_dent->d_inode != dent_inode)) {
/* This can happen because bad inodes are unhashed. */
BUG_ON(!is_bad_inode(dent_inode));
BUG_ON(!is_bad_inode(real_dent->d_inode));
}
/*
* Already have the inode and the dentry attached, decrement
* the reference count to balance the ntfs_iget() we did
* earlier on. We found the dentry using d_lookup() so it
* cannot be disconnected and thus we do not need to worry
* about any NFS/disconnectedness issues here.
*/
iput(dent_inode);
ntfs_debug("Done. (Already had inode and dentry.)");
return real_dent;
}
/*
* Negative dentry: instantiate it unless the inode is a directory and
* has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED),
* in which case d_move() that in place of the found dentry.
*/
if (!S_ISDIR(dent_inode->i_mode)) {
/* Not a directory; everything is easy. */
d_instantiate(real_dent, dent_inode);
ntfs_debug("Done. (Already had negative file dentry.)");
return real_dent;
}
spin_lock(&dcache_lock);
if (list_empty(&dent_inode->i_dentry)) {
/*
* Directory without a 'disconnected' dentry; we need to do
* d_instantiate() by hand because it takes dcache_lock which
* we already hold.
*/
list_add(&real_dent->d_alias, &dent_inode->i_dentry);
real_dent->d_inode = dent_inode;
spin_unlock(&dcache_lock);
security_d_instantiate(real_dent, dent_inode);
ntfs_debug("Done. (Already had negative directory dentry.)");
return real_dent;
}
/*
* Directory with a 'disconnected' dentry; get a reference to the
* 'disconnected' dentry.
*/
new_dent = list_entry(dent_inode->i_dentry.next, struct dentry,
d_alias);
dget_locked(new_dent);
spin_unlock(&dcache_lock);
/* Do security vodoo. */
security_d_instantiate(real_dent, dent_inode);
/* Move new_dent in place of real_dent. */
d_move(new_dent, real_dent);
/* Balance the ntfs_iget() we did above. */
iput(dent_inode);
/* Throw away real_dent. */
dput(real_dent);
/* Use new_dent as the actual dentry. */
ntfs_debug("Done. (Already had negative, disconnected directory "
"dentry.)");
return new_dent;
return dent;
eio_err_out:
ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
......
......@@ -330,6 +330,7 @@ static unsigned int get_inode_number(void)
spin_lock(&proc_inum_lock);
ida_remove(&proc_inum_ida, i);
spin_unlock(&proc_inum_lock);
return 0;
}
return PROC_DYNAMIC_FIRST + i;
}
......
......@@ -80,8 +80,10 @@ static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset
if (buf->result)
return -EINVAL;
d_ino = ino;
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
buf->result = -EOVERFLOW;
return -EOVERFLOW;
}
buf->result++;
dirent = buf->dirent;
if (!access_ok(VERIFY_WRITE, dirent,
......@@ -155,8 +157,10 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
if (reclen > buf->count)
return -EINVAL;
d_ino = ino;
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
buf->error = -EOVERFLOW;
return -EOVERFLOW;
}
dirent = buf->previous;
if (dirent) {
if (__put_user(offset, &dirent->d_off))
......
......@@ -108,9 +108,9 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
goto Done;
}
/* we need at least one record in buffer */
pos = m->index;
p = m->op->start(m, &pos);
while (1) {
pos = m->index;
p = m->op->start(m, &pos);
err = PTR_ERR(p);
if (!p || IS_ERR(p))
break;
......@@ -119,6 +119,11 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
break;
if (unlikely(err))
m->count = 0;
if (unlikely(!m->count)) {
p = m->op->next(m, p, &pos);
m->index = pos;
continue;
}
if (m->count < m->size)
goto Fill;
m->op->stop(m, p);
......@@ -128,6 +133,8 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
goto Enomem;
m->count = 0;
m->version = 0;
pos = m->index;
p = m->op->start(m, &pos);
}
m->op->stop(m, p);
m->count = 0;
......
......@@ -475,6 +475,7 @@ const struct file_operations xfs_invis_file_operations = {
const struct file_operations xfs_dir_file_operations = {
.read = generic_read_dir,
.readdir = xfs_file_readdir,
.llseek = generic_file_llseek,
.unlocked_ioctl = xfs_file_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = xfs_file_compat_ioctl,
......
......@@ -355,7 +355,7 @@ xfs_vn_ci_lookup(
/* else case-insensitive match... */
dname.name = ci_name.name;
dname.len = ci_name.len;
dentry = d_add_ci(VFS_I(ip), dentry, &dname);
dentry = d_add_ci(dentry, VFS_I(ip), &dname);
kmem_free(ci_name.name);
return dentry;
}
......
......@@ -230,7 +230,7 @@ extern void d_delete(struct dentry *);
extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
extern struct dentry * d_alloc_anon(struct inode *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
extern struct dentry * d_add_ci(struct inode *, struct dentry *, struct qstr *);
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
extern void shrink_dcache_sb(struct super_block *);
extern void shrink_dcache_parent(struct dentry *);
extern void shrink_dcache_for_umount(struct super_block *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment