Exemple #1
0
static int
coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
{
    struct coda_file_info *cfi;
    struct coda_inode_info *cii;
    struct file *host_file;
    struct inode *coda_inode, *host_inode;

    cfi = CODA_FTOC(coda_file);
    BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
    host_file = cfi->cfi_container;

    if (!host_file->f_op || !host_file->f_op->mmap)
        return -ENODEV;

    coda_inode = coda_file->f_path.dentry->d_inode;
    host_inode = host_file->f_path.dentry->d_inode;
    coda_file->f_mapping = host_file->f_mapping;
    if (coda_inode->i_mapping == &coda_inode->i_data)
        coda_inode->i_mapping = host_inode->i_mapping;

    /* only allow additional mmaps as long as userspace isn't changing
     * the container file on us! */
    else if (coda_inode->i_mapping != host_inode->i_mapping)
        return -EBUSY;

    /* keep track of how often the coda_inode/host_file has been mmapped */
    cii = ITOC(coda_inode);
    cii->c_mapcount++;
    cfi->cfi_mapcount++;

    return host_file->f_op->mmap(host_file, vma);
}
/* file operations for directories */
int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
{
	struct dentry *coda_dentry = coda_file->f_dentry;
	struct coda_file_info *cfi;
	struct file *host_file;
	int ret;

	cfi = CODA_FTOC(coda_file);
	if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG();
	host_file = cfi->cfi_container;

	coda_vfs_stat.readdir++;

	down(&host_file->f_dentry->d_inode->i_sem);
	host_file->f_pos = coda_file->f_pos;

	if ( !host_file->f_op->readdir ) {
		/* Venus: we must read Venus dirents from the file */
		ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
	} else {
		/* potemkin case: we were handed a directory inode */
		ret = vfs_readdir(host_file, filldir, dirent);
	}

	coda_file->f_pos = host_file->f_pos;
	up(&host_file->f_dentry->d_inode->i_sem);

	return ret;
}
int coda_release(struct inode *coda_inode, struct file *coda_file)
{
	unsigned short flags = (coda_file->f_flags) & (~O_EXCL);
	unsigned short coda_flags = coda_flags_to_cflags(flags);
	struct coda_file_info *cfi;
	struct coda_inode_info *cii;
	struct inode *host_inode;
	int err;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);

	err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
			  coda_flags, coda_file->f_cred->fsuid);

	host_inode = cfi->cfi_container->f_path.dentry->d_inode;
	cii = ITOC(coda_inode);

	/* did we mmap this file? */
	spin_lock(&cii->c_lock);
	if (coda_inode->i_mapping == &host_inode->i_data) {
		cii->c_mapcount -= cfi->cfi_mapcount;
		if (!cii->c_mapcount)
			coda_inode->i_mapping = &coda_inode->i_data;
	}
	spin_unlock(&cii->c_lock);

	fput(cfi->cfi_container);
	kfree(coda_file->private_data);
	coda_file->private_data = NULL;

	/* VFS fput ignores the return value from file_operations->release, so
	 * there is no use returning an error here */
	return 0;
}
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
{
	struct file *host_file;
	struct dentry *host_dentry;
	struct inode *host_inode, *coda_inode = coda_dentry->d_inode;
	struct coda_file_info *cfi;
	int err = 0;

	if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
	      S_ISLNK(coda_inode->i_mode)))
		return -EINVAL;

	cfi = CODA_FTOC(coda_file);
	if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG();
	host_file = cfi->cfi_container;

	coda_vfs_stat.fsync++;

	if (host_file->f_op && host_file->f_op->fsync) {
		host_dentry = host_file->f_dentry;
		host_inode = host_dentry->d_inode;
		down(&host_inode->i_sem);
		err = host_file->f_op->fsync(host_file, host_dentry, datasync);
		up(&host_inode->i_sem);
	}

	if ( !err && !datasync ) {
		lock_kernel();
		err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
		unlock_kernel();
	}

	return err;
}
static ssize_t
coda_file_write(struct file *coda_file, const char *buf, size_t count, loff_t *ppos)
{
	struct inode *coda_inode = coda_file->f_dentry->d_inode;
	struct coda_file_info *cfi;
	struct file *host_file;
	ssize_t ret;

	cfi = CODA_FTOC(coda_file);
	if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG();
	host_file = cfi->cfi_container;

	if (!host_file->f_op || !host_file->f_op->write)
		return -EINVAL;

	down(&coda_inode->i_sem);

	ret = host_file->f_op->write(host_file, buf, count, ppos);

	coda_inode->i_size = host_file->f_dentry->d_inode->i_size;
	coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
	coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME;
	up(&coda_inode->i_sem);

	return ret;
}
int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync)
{
	struct file *host_file;
	struct inode *coda_inode = coda_file->f_path.dentry->d_inode;
	struct coda_file_info *cfi;
	int err;

	if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
	      S_ISLNK(coda_inode->i_mode)))
		return -EINVAL;

	err = filemap_write_and_wait_range(coda_inode->i_mapping, start, end);
	if (err)
		return err;
	mutex_lock(&coda_inode->i_mutex);

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	err = vfs_fsync(host_file, datasync);
	if (!err && !datasync)
		err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
	mutex_unlock(&coda_inode->i_mutex);

	return err;
}
Exemple #7
0
static ssize_t
coda_file_write(struct file *coda_file, const char __user *buf, size_t count, loff_t *ppos)
{
    struct inode *host_inode, *coda_inode = coda_file->f_path.dentry->d_inode;
    struct coda_file_info *cfi;
    struct file *host_file;
    ssize_t ret;

    cfi = CODA_FTOC(coda_file);
    BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
    host_file = cfi->cfi_container;

    if (!host_file->f_op || !host_file->f_op->write)
        return -EINVAL;

    host_inode = host_file->f_path.dentry->d_inode;
    mutex_lock(&coda_inode->i_mutex);

    ret = host_file->f_op->write(host_file, buf, count, ppos);

    coda_inode->i_size = host_inode->i_size;
    coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
    coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME_SEC;
    mutex_unlock(&coda_inode->i_mutex);

    return ret;
}
static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
{
	struct coda_file_info *cfi;
	struct file *host_file;
	int ret;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	if (!host_file->f_op)
		return -ENOTDIR;

	if (host_file->f_op->readdir)
	{
		struct inode *host_inode = host_file->f_path.dentry->d_inode;

		mutex_lock(&host_inode->i_mutex);
		host_file->f_pos = coda_file->f_pos;

		ret = -ENOENT;
		if (!IS_DEADDIR(host_inode)) {
			ret = host_file->f_op->readdir(host_file, buf, filldir);
			file_accessed(host_file);
		}

		coda_file->f_pos = host_file->f_pos;
		mutex_unlock(&host_inode->i_mutex);
	}
	else 
		ret = coda_venus_readdir(coda_file, buf, filldir);

	return ret;
}
Exemple #9
0
static ssize_t
coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
	struct file *coda_file = iocb->ki_filp;
	struct coda_file_info *cfi = CODA_FTOC(coda_file);

	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);

	return vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos);
}
Exemple #10
0
static ssize_t
coda_file_read(struct file *coda_file, char __user *buf, size_t count, loff_t *ppos)
{
    struct coda_file_info *cfi;
    struct file *host_file;

    cfi = CODA_FTOC(coda_file);
    BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
    host_file = cfi->cfi_container;

    if (!host_file->f_op || !host_file->f_op->read)
        return -EINVAL;

    return host_file->f_op->read(host_file, buf, count, ppos);
}
Exemple #11
0
static ssize_t
coda_file_sendfile(struct file *coda_file, loff_t *ppos, size_t count,
		   read_actor_t actor, void *target)
{
	struct coda_file_info *cfi;
	struct file *host_file;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	if (!host_file->f_op || !host_file->f_op->sendfile)
		return -EINVAL;

	return host_file->f_op->sendfile(host_file, ppos, count, actor, target);
}
Exemple #12
0
static ssize_t
coda_file_splice_read(struct file *coda_file, loff_t *ppos,
                      struct pipe_inode_info *pipe, size_t count,
                      unsigned int flags)
{
    struct coda_file_info *cfi;
    struct file *host_file;

    cfi = CODA_FTOC(coda_file);
    BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
    host_file = cfi->cfi_container;

    if (!host_file->f_op || !host_file->f_op->splice_read)
        return -EINVAL;

    return host_file->f_op->splice_read(host_file, ppos, pipe, count,flags);
}
int coda_release(struct inode *coda_inode, struct file *coda_file)
{
	unsigned short flags = (coda_file->f_flags) & (~O_EXCL);
	unsigned short coda_flags = coda_flags_to_cflags(flags);
	struct coda_file_info *cfi;
	struct coda_inode_info *cii;
	struct inode *host_inode;
	int err = 0;

	lock_kernel();
	coda_vfs_stat.release++;
 
	if (!use_coda_close) {
		err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode),
				    coda_flags);
		if (err == -EOPNOTSUPP) {
			use_coda_close = 1;
			err = 0;
		}
	}

	cfi = CODA_FTOC(coda_file);
	if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG();

	if (use_coda_close)
		err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
				  coda_flags, &cfi->cfi_cred);

	host_inode = cfi->cfi_container->f_dentry->d_inode;
	cii = ITOC(coda_inode);

	/* did we mmap this file? */
	if (coda_inode->i_mapping == &host_inode->i_data) {
		cii->c_mapcount -= cfi->cfi_mapcount;
		if (!cii->c_mapcount)
			coda_inode->i_mapping = &coda_inode->i_data;
	}

	fput(cfi->cfi_container);

	kfree(coda_file->private_data);
	coda_file->private_data = NULL;

	unlock_kernel();
	return err;
}
Exemple #14
0
int coda_flush(struct file *coda_file, fl_owner_t id)
{
	unsigned short flags = coda_file->f_flags & ~O_EXCL;
	unsigned short coda_flags = coda_flags_to_cflags(flags);
	struct coda_file_info *cfi;
	struct inode *coda_inode;
	int err = 0, fcnt;

	lock_kernel();

	coda_vfs_stat.flush++;

	/* last close semantics */
	fcnt = file_count(coda_file);
	if (fcnt > 1)
		goto out;

	/* No need to make an upcall when we have not made any modifications
	 * to the file */
	if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY)
		goto out;

	if (use_coda_close)
		goto out;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);

	coda_inode = coda_file->f_dentry->d_inode;

	err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
			  coda_file->f_uid);

	if (err == -EOPNOTSUPP) {
		use_coda_close = 1;
		err = 0;
	}

out:
	unlock_kernel();
	return err;
}
static ssize_t
coda_file_splice_read(struct file *coda_file, loff_t *ppos,
		      struct pipe_inode_info *pipe, size_t count,
		      unsigned int flags)
{
	ssize_t (*splice_read)(struct file *, loff_t *,
			       struct pipe_inode_info *, size_t, unsigned int);
	struct coda_file_info *cfi;
	struct file *host_file;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	splice_read = host_file->f_op->splice_read;
	if (!splice_read)
		splice_read = default_file_splice_read;

	return splice_read(host_file, ppos, pipe, count, flags);
}
Exemple #16
0
/* file operations for directories */
int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
{
	struct dentry *coda_dentry = coda_file->f_path.dentry;
	struct coda_file_info *cfi;
	struct file *host_file;
	struct inode *host_inode;
	int ret;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	coda_vfs_stat.readdir++;

	host_inode = host_file->f_path.dentry->d_inode;
	mutex_lock(&host_inode->i_mutex);
	host_file->f_pos = coda_file->f_pos;

	if (!host_file->f_op->readdir) {
		/* Venus: we must read Venus dirents from the file */
		ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
	} else {
		/* potemkin case: we were handed a directory inode. */
		/* Yuk, we can't call vfs_readdir because we are already
		 * holding the inode semaphore. */
		ret = -ENOTDIR;
		if (!host_file->f_op || !host_file->f_op->readdir)
			goto out;

		ret = -ENOENT;
		if (!IS_DEADDIR(host_inode)) {
			ret = host_file->f_op->readdir(host_file, filldir, dirent);
			file_accessed(host_file);
		}
	}
out:
	coda_file->f_pos = host_file->f_pos;
	mutex_unlock(&host_inode->i_mutex);

	return ret;
}
Exemple #17
0
static ssize_t
coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
{
	struct file *coda_file = iocb->ki_filp;
	struct inode *coda_inode = file_inode(coda_file);
	struct coda_file_info *cfi = CODA_FTOC(coda_file);
	struct file *host_file;
	ssize_t ret;

	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);

	host_file = cfi->cfi_container;
	file_start_write(host_file);
	inode_lock(coda_inode);
	ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos);
	coda_inode->i_size = file_inode(host_file)->i_size;
	coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
	coda_inode->i_mtime = coda_inode->i_ctime = current_time(coda_inode);
	inode_unlock(coda_inode);
	file_end_write(host_file);
	return ret;
}
Exemple #18
0
/* file operations for directories */
static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
{
	struct coda_file_info *cfi;
	struct file *host_file;
	int ret;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	if (!host_file->f_op)
		return -ENOTDIR;

	if (host_file->f_op->readdir)
	{
		/* potemkin case: we were handed a directory inode.
		 * We can't use vfs_readdir because we have to keep the file
		 * position in sync between the coda_file and the host_file.
		 * and as such we need grab the inode mutex. */
		struct inode *host_inode = host_file->f_path.dentry->d_inode;

		mutex_lock(&host_inode->i_mutex);
		host_file->f_pos = coda_file->f_pos;

		ret = -ENOENT;
		if (!IS_DEADDIR(host_inode)) {
			ret = host_file->f_op->readdir(host_file, buf, filldir);
			file_accessed(host_file);
		}

		coda_file->f_pos = host_file->f_pos;
		mutex_unlock(&host_inode->i_mutex);
	}
	else /* Venus: we must read Venus dirents from a file */
		ret = coda_venus_readdir(coda_file, buf, filldir);

	return ret;
}
Exemple #19
0
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
{
    struct file *host_file;
    struct inode *coda_inode = coda_dentry->d_inode;
    struct coda_file_info *cfi;
    int err = 0;

    if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
            S_ISLNK(coda_inode->i_mode)))
        return -EINVAL;

    cfi = CODA_FTOC(coda_file);
    BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
    host_file = cfi->cfi_container;

    err = vfs_fsync(host_file, host_file->f_path.dentry, datasync);
    if ( !err && !datasync ) {
        lock_kernel();
        err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
        unlock_kernel();
    }

    return err;
}
Exemple #20
0
/* file operations for directories */
static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
{
    struct coda_file_info *cfi;
    struct file *host_file;
    int ret;

    cfi = CODA_FTOC(coda_file);
    BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
    host_file = cfi->cfi_container;

    if (host_file->f_op->iterate) {
        struct inode *host_inode = file_inode(host_file);
        mutex_lock(&host_inode->i_mutex);
        ret = -ENOENT;
        if (!IS_DEADDIR(host_inode)) {
            ret = host_file->f_op->iterate(host_file, ctx);
            file_accessed(host_file);
        }
        mutex_unlock(&host_inode->i_mutex);
        return ret;
    }
    /* Venus: we must read Venus dirents from a file */
    return coda_venus_readdir(coda_file, ctx);
}
int coda_flush(struct file *coda_file)
{
	unsigned short flags = coda_file->f_flags & ~O_EXCL;
	unsigned short coda_flags = coda_flags_to_cflags(flags);
	struct coda_file_info *cfi;
	struct inode *coda_inode;
	int err = 0, fcnt;

	coda_vfs_stat.flush++;

	/* No need to make an upcall when we have not made any modifications
	 * to the file */
	if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY)
		return 0;

	if (use_coda_close)
		return 0;

	fcnt = file_count(coda_file);
	if (fcnt > 1) return 0;

	coda_inode = coda_file->f_dentry->d_inode;

	cfi = CODA_FTOC(coda_file);
	if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG();

	err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
			  &cfi->cfi_cred);

	if (err == -EOPNOTSUPP) {
		use_coda_close = 1;
		err = 0;
	}

	return err;
}
Exemple #22
0
/* support routines */
static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
{
    struct coda_file_info *cfi;
    struct coda_inode_info *cii;
    struct file *host_file;
    struct venus_dirent *vdir;
    unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
    unsigned int type;
    struct qstr name;
    ino_t ino;
    int ret;

    cfi = CODA_FTOC(coda_file);
    BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
    host_file = cfi->cfi_container;

    cii = ITOC(file_inode(coda_file));

    vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
    if (!vdir) return -ENOMEM;

    if (!dir_emit_dots(coda_file, ctx))
        goto out;

    while (1) {
        /* read entries from the directory file */
        ret = kernel_read(host_file, ctx->pos - 2, (char *)vdir,
                          sizeof(*vdir));
        if (ret < 0) {
            pr_err("%s: read dir %s failed %d\n",
                   __func__, coda_f2s(&cii->c_fid), ret);
            break;
        }
        if (ret == 0) break; /* end of directory file reached */

        /* catch truncated reads */
        if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
            pr_err("%s: short read on %s\n",
                   __func__, coda_f2s(&cii->c_fid));
            ret = -EBADF;
            break;
        }
        /* validate whether the directory file actually makes sense */
        if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
            pr_err("%s: invalid dir %s\n",
                   __func__, coda_f2s(&cii->c_fid));
            ret = -EBADF;
            break;
        }

        name.len = vdir->d_namlen;
        name.name = vdir->d_name;

        /* Make sure we skip '.' and '..', we already got those */
        if (name.name[0] == '.' && (name.len == 1 ||
                                    (name.name[1] == '.' && name.len == 2)))
            vdir->d_fileno = name.len = 0;

        /* skip null entries */
        if (vdir->d_fileno && name.len) {
            ino = vdir->d_fileno;
            type = CDT2DT(vdir->d_type);
            if (!dir_emit(ctx, name.name, name.len, ino, type))
                break;
        }
        /* we'll always have progress because d_reclen is unsigned and
         * we've already established it is non-zero. */
        ctx->pos += vdir->d_reclen;
    }
out:
    kfree(vdir);
    return 0;
}
static int coda_venus_readdir(struct file *coda_file, void *buf,
			      filldir_t filldir)
{
	int result = 0; 
	struct coda_file_info *cfi;
	struct coda_inode_info *cii;
	struct file *host_file;
	struct dentry *de;
	struct venus_dirent *vdir;
	unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
	unsigned int type;
	struct qstr name;
	ino_t ino;
	int ret;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	de = coda_file->f_path.dentry;
	cii = ITOC(de->d_inode);

	vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
	if (!vdir) return -ENOMEM;

	if (coda_file->f_pos == 0) {
		ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR);
		if (ret < 0)
			goto out;
		result++;
		coda_file->f_pos++;
	}
	if (coda_file->f_pos == 1) {
		ret = filldir(buf, "..", 2, 1, parent_ino(de), DT_DIR);
		if (ret < 0)
			goto out;
		result++;
		coda_file->f_pos++;
	}
	while (1) {
		
		ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir,
				  sizeof(*vdir));
		if (ret < 0) {
			printk(KERN_ERR "coda readdir: read dir %s failed %d\n",
			       coda_f2s(&cii->c_fid), ret);
			break;
		}
		if (ret == 0) break; 

		
		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
			printk(KERN_ERR "coda readdir: short read on %s\n",
			       coda_f2s(&cii->c_fid));
			ret = -EBADF;
			break;
		}
		
		if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
			printk(KERN_ERR "coda readdir: invalid dir %s\n",
			       coda_f2s(&cii->c_fid));
			ret = -EBADF;
			break;
		}

		name.len = vdir->d_namlen;
		name.name = vdir->d_name;

		
		if (name.name[0] == '.' && (name.len == 1 ||
		    (vdir->d_name[1] == '.' && name.len == 2)))
			vdir->d_fileno = name.len = 0;

		
		if (vdir->d_fileno && name.len) {
			ino = find_inode_number(de, &name);
			if (!ino) ino = vdir->d_fileno;

			type = CDT2DT(vdir->d_type);
			ret = filldir(buf, name.name, name.len,
				      coda_file->f_pos, ino, type);
			
			if (ret < 0) break;
			result++;
		}
		coda_file->f_pos += vdir->d_reclen;
	}
out:
	kfree(vdir);
	return result ? result : ret;
}
Exemple #24
0
/* support routines */
static int coda_venus_readdir(struct file *coda_file, void *buf,
			      filldir_t filldir)
{
	int result = 0; /* # of entries returned */
	struct coda_file_info *cfi;
	struct coda_inode_info *cii;
	struct file *host_file;
	struct dentry *de;
	struct venus_dirent *vdir;
	unsigned long vdir_size =
	    (unsigned long)(&((struct venus_dirent *)0)->d_name);
	unsigned int type;
	struct qstr name;
	ino_t ino;
	int ret;

	cfi = CODA_FTOC(coda_file);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	de = coda_file->f_path.dentry;
	cii = ITOC(de->d_inode);

	vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
	if (!vdir) return -ENOMEM;

	if (coda_file->f_pos == 0) {
		ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR);
		if (ret < 0)
			goto out;
		result++;
		coda_file->f_pos++;
	}
	if (coda_file->f_pos == 1) {
		ret = filldir(buf, "..", 2, 1, de->d_parent->d_inode->i_ino, DT_DIR);
		if (ret < 0)
			goto out;
		result++;
		coda_file->f_pos++;
	}
	while (1) {
		/* read entries from the directory file */
		ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir,
				  sizeof(*vdir));
		if (ret < 0) {
			printk(KERN_ERR "coda readdir: read dir %s failed %d\n",
			       coda_f2s(&cii->c_fid), ret);
			break;
		}
		if (ret == 0) break; /* end of directory file reached */

		/* catch truncated reads */
		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
			printk(KERN_ERR "coda readdir: short read on %s\n",
			       coda_f2s(&cii->c_fid));
			ret = -EBADF;
			break;
		}
		/* validate whether the directory file actually makes sense */
		if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
			printk(KERN_ERR "coda readdir: invalid dir %s\n",
			       coda_f2s(&cii->c_fid));
			ret = -EBADF;
			break;
		}

		name.len = vdir->d_namlen;
		name.name = vdir->d_name;

		/* Make sure we skip '.' and '..', we already got those */
		if (name.name[0] == '.' && (name.len == 1 ||
		    (vdir->d_name[1] == '.' && name.len == 2)))
			vdir->d_fileno = name.len = 0;

		/* skip null entries */
		if (vdir->d_fileno && name.len) {
			/* try to look up this entry in the dcache, that way
			 * userspace doesn't have to worry about breaking
			 * getcwd by having mismatched inode numbers for
			 * internal volume mountpoints. */
			ino = find_inode_number(de, &name);
			if (!ino) ino = vdir->d_fileno;

			type = CDT2DT(vdir->d_type);
			ret = filldir(buf, name.name, name.len,
				      coda_file->f_pos, ino, type);
			/* failure means no space for filling in this round */
			if (ret < 0) break;
			result++;
		}
		/* we'll always have progress because d_reclen is unsigned and
		 * we've already established it is non-zero. */
		coda_file->f_pos += vdir->d_reclen;
	}
out:
	kfree(vdir);
	return result ? result : ret;
}