mirror of
https://github.com/torvalds/linux.git
synced 2024-11-06 03:51:48 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: [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
This commit is contained in:
commit
5b51a7e9d8
@ -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 @@ out:
|
||||
|
||||
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 @@ handle_name:
|
||||
}
|
||||
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 @@ retry:
|
||||
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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user