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, ...@@ -121,24 +121,29 @@ osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
if (reclen > buf->count) if (reclen > buf->count)
return -EINVAL; return -EINVAL;
d_ino = ino; 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; return -EOVERFLOW;
}
if (buf->basep) { if (buf->basep) {
if (put_user(offset, buf->basep)) if (put_user(offset, buf->basep))
return -EFAULT; goto Efault;
buf->basep = NULL; buf->basep = NULL;
} }
dirent = buf->dirent; dirent = buf->dirent;
put_user(d_ino, &dirent->d_ino); if (put_user(d_ino, &dirent->d_ino) ||
put_user(namlen, &dirent->d_namlen); put_user(namlen, &dirent->d_namlen) ||
put_user(reclen, &dirent->d_reclen); put_user(reclen, &dirent->d_reclen) ||
if (copy_to_user(dirent->d_name, name, namlen) || copy_to_user(dirent->d_name, name, namlen) ||
put_user(0, dirent->d_name + namlen)) put_user(0, dirent->d_name + namlen))
return -EFAULT; goto Efault;
dirent = (void __user *)dirent + reclen; dirent = (void __user *)dirent + reclen;
buf->dirent = dirent; buf->dirent = dirent;
buf->count -= reclen; buf->count -= reclen;
return 0; return 0;
Efault:
buf->error = -EFAULT;
return -EFAULT;
} }
asmlinkage int asmlinkage int
......
...@@ -84,22 +84,28 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, ...@@ -84,22 +84,28 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
if (reclen > buf->count) if (reclen > buf->count)
return -EINVAL; return -EINVAL;
d_ino = ino; 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; return -EOVERFLOW;
}
dirent = buf->previous; dirent = buf->previous;
if (dirent) if (dirent)
put_user(offset, &dirent->d_off); if (put_user(offset, &dirent->d_off))
goto Efault;
dirent = buf->current_dir; 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; buf->previous = dirent;
put_user(d_ino, &dirent->d_ino); buf->current_dir = (void __user *)dirent + reclen;
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->count -= reclen; buf->count -= reclen;
return 0; return 0;
Efault:
buffer->error = -EFAULT;
return -EFAULT;
} }
#undef NAME_OFFSET #undef NAME_OFFSET
...@@ -126,7 +132,9 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i ...@@ -126,7 +132,9 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
error = buf.error; error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;
if (lastdirent) { if (lastdirent) {
put_user(file->f_pos, &lastdirent->d_off); if (put_user(file->f_pos, &lastdirent->d_off))
error = -EFAULT;
else
error = count - buf.count; error = count - buf.count;
} }
......
...@@ -119,6 +119,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) ...@@ -119,6 +119,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
const struct file_operations v9fs_dir_operations = { const struct file_operations v9fs_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = v9fs_dir_readdir, .readdir = v9fs_dir_readdir,
.open = v9fs_file_open, .open = v9fs_file_open,
.release = v9fs_dir_release, .release = v9fs_dir_release,
......
...@@ -197,6 +197,7 @@ adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_inf ...@@ -197,6 +197,7 @@ adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_inf
const struct file_operations adfs_dir_operations = { const struct file_operations adfs_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = adfs_readdir, .readdir = adfs_readdir,
.fsync = file_fsync, .fsync = file_fsync,
}; };
......
...@@ -19,6 +19,7 @@ static int affs_readdir(struct file *, void *, filldir_t); ...@@ -19,6 +19,7 @@ static int affs_readdir(struct file *, void *, filldir_t);
const struct file_operations affs_dir_operations = { const struct file_operations affs_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = affs_readdir, .readdir = affs_readdir,
.fsync = file_fsync, .fsync = file_fsync,
}; };
......
...@@ -36,6 +36,7 @@ const struct file_operations autofs4_root_operations = { ...@@ -36,6 +36,7 @@ const struct file_operations autofs4_root_operations = {
.release = dcache_dir_close, .release = dcache_dir_close,
.read = generic_read_dir, .read = generic_read_dir,
.readdir = dcache_readdir, .readdir = dcache_readdir,
.llseek = dcache_dir_lseek,
.ioctl = autofs4_root_ioctl, .ioctl = autofs4_root_ioctl,
}; };
...@@ -44,6 +45,7 @@ const struct file_operations autofs4_dir_operations = { ...@@ -44,6 +45,7 @@ const struct file_operations autofs4_dir_operations = {
.release = dcache_dir_close, .release = dcache_dir_close,
.read = generic_read_dir, .read = generic_read_dir,
.readdir = dcache_readdir, .readdir = dcache_readdir,
.llseek = dcache_dir_lseek,
}; };
const struct inode_operations autofs4_indirect_root_inode_operations = { const struct inode_operations autofs4_indirect_root_inode_operations = {
......
...@@ -66,6 +66,7 @@ static struct kmem_cache *befs_inode_cachep; ...@@ -66,6 +66,7 @@ static struct kmem_cache *befs_inode_cachep;
static const struct file_operations befs_dir_operations = { static const struct file_operations befs_dir_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = befs_readdir, .readdir = befs_readdir,
.llseek = generic_file_llseek,
}; };
static const struct inode_operations befs_dir_inode_operations = { static const struct inode_operations befs_dir_inode_operations = {
......
...@@ -792,8 +792,10 @@ static int compat_fillonedir(void *__buf, const char *name, int namlen, ...@@ -792,8 +792,10 @@ static int compat_fillonedir(void *__buf, const char *name, int namlen,
if (buf->result) if (buf->result)
return -EINVAL; return -EINVAL;
d_ino = ino; 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; return -EOVERFLOW;
}
buf->result++; buf->result++;
dirent = buf->dirent; dirent = buf->dirent;
if (!access_ok(VERIFY_WRITE, dirent, if (!access_ok(VERIFY_WRITE, dirent,
...@@ -862,8 +864,10 @@ static int compat_filldir(void *__buf, const char *name, int namlen, ...@@ -862,8 +864,10 @@ static int compat_filldir(void *__buf, const char *name, int namlen,
if (reclen > buf->count) if (reclen > buf->count)
return -EINVAL; return -EINVAL;
d_ino = ino; 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; return -EOVERFLOW;
}
dirent = buf->previous; dirent = buf->previous;
if (dirent) { if (dirent) {
if (__put_user(offset, &dirent->d_off)) if (__put_user(offset, &dirent->d_off))
......
...@@ -1236,7 +1236,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) ...@@ -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 * If no entry exists with the exact case name, allocate new dentry with
* the exact case, and return the spliced entry. * 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) struct qstr *name)
{ {
int error; int error;
......
...@@ -74,8 +74,7 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei ...@@ -74,8 +74,7 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
} }
unlock_kernel(); unlock_kernel();
d_add(dentry, inode); return d_splice_alias(inode, dentry);
return NULL;
} }
static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino, 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, ...@@ -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) // TODO: Consider moving this lot to a separate function! (AIA)
handle_name: handle_name:
{ {
struct dentry *real_dent, *new_dent;
MFT_RECORD *m; MFT_RECORD *m;
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
ntfs_inode *ni = NTFS_I(dent_inode); ntfs_inode *ni = NTFS_I(dent_inode);
...@@ -255,93 +254,9 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, ...@@ -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); nls_name.hash = full_name_hash(nls_name.name, nls_name.len);
/* dent = d_add_ci(dent, dent_inode, &nls_name);
* 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); kfree(nls_name.name);
if (!real_dent) { return 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;
}
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;
eio_err_out: eio_err_out:
ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk."); ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
......
...@@ -330,6 +330,7 @@ static unsigned int get_inode_number(void) ...@@ -330,6 +330,7 @@ static unsigned int get_inode_number(void)
spin_lock(&proc_inum_lock); spin_lock(&proc_inum_lock);
ida_remove(&proc_inum_ida, i); ida_remove(&proc_inum_ida, i);
spin_unlock(&proc_inum_lock); spin_unlock(&proc_inum_lock);
return 0;
} }
return PROC_DYNAMIC_FIRST + i; return PROC_DYNAMIC_FIRST + i;
} }
......
...@@ -80,8 +80,10 @@ static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset ...@@ -80,8 +80,10 @@ static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset
if (buf->result) if (buf->result)
return -EINVAL; return -EINVAL;
d_ino = ino; 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; return -EOVERFLOW;
}
buf->result++; buf->result++;
dirent = buf->dirent; dirent = buf->dirent;
if (!access_ok(VERIFY_WRITE, dirent, if (!access_ok(VERIFY_WRITE, dirent,
...@@ -155,8 +157,10 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, ...@@ -155,8 +157,10 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
if (reclen > buf->count) if (reclen > buf->count)
return -EINVAL; return -EINVAL;
d_ino = ino; 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; return -EOVERFLOW;
}
dirent = buf->previous; dirent = buf->previous;
if (dirent) { if (dirent) {
if (__put_user(offset, &dirent->d_off)) 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) ...@@ -108,9 +108,9 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
goto Done; goto Done;
} }
/* we need at least one record in buffer */ /* we need at least one record in buffer */
while (1) {
pos = m->index; pos = m->index;
p = m->op->start(m, &pos); p = m->op->start(m, &pos);
while (1) {
err = PTR_ERR(p); err = PTR_ERR(p);
if (!p || IS_ERR(p)) if (!p || IS_ERR(p))
break; break;
...@@ -119,6 +119,11 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) ...@@ -119,6 +119,11 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
break; break;
if (unlikely(err)) if (unlikely(err))
m->count = 0; m->count = 0;
if (unlikely(!m->count)) {
p = m->op->next(m, p, &pos);
m->index = pos;
continue;
}
if (m->count < m->size) if (m->count < m->size)
goto Fill; goto Fill;
m->op->stop(m, p); 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) ...@@ -128,6 +133,8 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
goto Enomem; goto Enomem;
m->count = 0; m->count = 0;
m->version = 0; m->version = 0;
pos = m->index;
p = m->op->start(m, &pos);
} }
m->op->stop(m, p); m->op->stop(m, p);
m->count = 0; m->count = 0;
......
...@@ -475,6 +475,7 @@ const struct file_operations xfs_invis_file_operations = { ...@@ -475,6 +475,7 @@ const struct file_operations xfs_invis_file_operations = {
const struct file_operations xfs_dir_file_operations = { const struct file_operations xfs_dir_file_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = xfs_file_readdir, .readdir = xfs_file_readdir,
.llseek = generic_file_llseek,
.unlocked_ioctl = xfs_file_ioctl, .unlocked_ioctl = xfs_file_ioctl,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = xfs_file_compat_ioctl, .compat_ioctl = xfs_file_compat_ioctl,
......
...@@ -355,7 +355,7 @@ xfs_vn_ci_lookup( ...@@ -355,7 +355,7 @@ xfs_vn_ci_lookup(
/* else case-insensitive match... */ /* else case-insensitive match... */
dname.name = ci_name.name; dname.name = ci_name.name;
dname.len = ci_name.len; 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); kmem_free(ci_name.name);
return dentry; return dentry;
} }
......
...@@ -230,7 +230,7 @@ extern void d_delete(struct 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(struct dentry *, const struct qstr *);
extern struct dentry * d_alloc_anon(struct inode *); 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 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_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 *);
......
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