alistair23-linux/fs/9p/vfs_dir.c
Eric Van Hensbergen 06b55b464e 9p: move dirread to fs layer
Currently reading a directory is implemented in the client code.
This function is not actually a wire operation, but a meta operation 
which calls read operations and processes the results.

This patch moves this functionality to the fs layer and calls component
wire operations instead of constructing their packets.  This provides a 
cleaner separation and will help when we reorganize the client functions
and protocol processing methods.

Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
2008-10-17 11:04:43 -05:00

149 lines
3.2 KiB
C

/*
* linux/fs/9p/vfs_dir.c
*
* This file contains vfs directory ops for the 9P2000 protocol.
*
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to:
* Free Software Foundation
* 51 Franklin Street, Fifth Floor
* Boston, MA 02111-1301 USA
*
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/inet.h>
#include <linux/idr.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
#include "v9fs.h"
#include "v9fs_vfs.h"
#include "fid.h"
/**
* dt_type - return file type
* @mistat: mistat structure
*
*/
static inline int dt_type(struct p9_stat *mistat)
{
unsigned long perm = mistat->mode;
int rettype = DT_REG;
if (perm & P9_DMDIR)
rettype = DT_DIR;
if (perm & P9_DMSYMLINK)
rettype = DT_LNK;
return rettype;
}
/**
* v9fs_dir_readdir - read a directory
* @filp: opened file structure
* @dirent: directory structure ???
* @filldir: function to populate directory structure ???
*
*/
static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
int over;
struct p9_stat st;
int err;
struct p9_fid *fid;
int buflen;
char *statbuf;
int n, i = 0;
P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
fid = filp->private_data;
buflen = fid->clnt->msize - P9_IOHDRSZ;
statbuf = kmalloc(buflen, GFP_KERNEL);
if (!statbuf)
return -ENOMEM;
while (1) {
err = v9fs_file_readn(filp, statbuf, NULL, fid->rdir_fpos,
buflen);
if (err <= 0)
break;
n = err;
while (i < n) {
err = p9_deserialize_stat(statbuf + i, buflen-i, &st,
fid->clnt->dotu);
if (!err) {
err = -EIO;
goto free_and_exit;
}
i += err;
fid->rdir_fpos += err;
over = filldir(dirent, st.name.str, st.name.len,
filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st));
filp->f_pos += st.size;
if (over) {
err = 0;
goto free_and_exit;
}
}
}
free_and_exit:
kfree(statbuf);
return err;
}
/**
* v9fs_dir_release - close a directory
* @inode: inode of the directory
* @filp: file pointer to a directory
*
*/
int v9fs_dir_release(struct inode *inode, struct file *filp)
{
struct p9_fid *fid;
fid = filp->private_data;
P9_DPRINTK(P9_DEBUG_VFS,
"inode: %p filp: %p fid: %d\n", inode, filp, fid->fid);
filemap_write_and_wait(inode->i_mapping);
p9_client_clunk(fid);
return 0;
}
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,
};