Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/ericvh/v9fs

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: (22 commits)
  9p: fix sparse warnings in new xattr code
  fs/9p: remove sparse warning in vfs_inode
  fs/9p: destroy fid on failed remove
  fs/9p: Prevent parallel rename when doing fid_lookup
  fs/9p: Add support user. xattr
  net/9p: Implement TXATTRCREATE 9p call
  net/9p: Implement attrwalk 9p call
  9p: Implement LOPEN
  fs/9p: This patch implements TLCREATE for 9p2000.L protocol.
  9p: Implement TMKDIR
  9p: Implement TMKNOD
  9p: Define and implement TSYMLINK for 9P2000.L
  9p: Define and implement TLINK for 9P2000.L
  9p: Define and implement TLINK for 9P2000.L
  9p: Implement client side of setattr for 9P2000.L protocol.
  9p: getattr client implementation for 9P2000.L protocol.
  fs/9p: Pass the correct user credentials during attach
  net/9p: Handle the server returned error properly
  9p: readdir implementation for 9p2000.L
  9p: Make use of iounit for read/write
  ...
  • Loading branch information
Linus Torvalds committed Aug 3, 2010
2 parents 51102ee + 327aec0 commit b8b3e90
Show file tree
Hide file tree
Showing 18 changed files with 1,845 additions and 123 deletions.
4 changes: 3 additions & 1 deletion fs/9p/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ obj-$(CONFIG_9P_FS) := 9p.o
vfs_dir.o \
vfs_dentry.o \
v9fs.o \
fid.o
fid.o \
xattr.o \
xattr_user.o

9p-$(CONFIG_9P_FSCACHE) += cache.o
111 changes: 77 additions & 34 deletions fs/9p/fid.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,34 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
return ret;
}

/*
* We need to hold v9ses->rename_sem as long as we hold references
* to returned path array. Array element contain pointers to
* dentry names.
*/
static int build_path_from_dentry(struct v9fs_session_info *v9ses,
struct dentry *dentry, char ***names)
{
int n = 0, i;
char **wnames;
struct dentry *ds;

for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
n++;

wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
if (!wnames)
goto err_out;

for (ds = dentry, i = (n-1); i >= 0; i--, ds = ds->d_parent)
wnames[i] = (char *)ds->d_name.name;

*names = wnames;
return n;
err_out:
return -ENOMEM;
}

/**
* v9fs_fid_lookup - lookup for a fid, try to walk if not found
* @dentry: dentry to look for fid in
Expand All @@ -112,7 +140,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
int i, n, l, clone, any, access;
u32 uid;
struct p9_fid *fid, *old_fid = NULL;
struct dentry *d, *ds;
struct dentry *ds;
struct v9fs_session_info *v9ses;
char **wnames, *uname;

Expand All @@ -139,49 +167,62 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
fid = v9fs_fid_find(dentry, uid, any);
if (fid)
return fid;

/*
* we don't have a matching fid. To do a TWALK we need
* parent fid. We need to prevent rename when we want to
* look at the parent.
*/
down_read(&v9ses->rename_sem);
ds = dentry->d_parent;
fid = v9fs_fid_find(ds, uid, any);
if (!fid) { /* walk from the root */
n = 0;
for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
n++;
if (fid) {
/* Found the parent fid do a lookup with that */
fid = p9_client_walk(fid, 1, (char **)&dentry->d_name.name, 1);
goto fid_out;
}
up_read(&v9ses->rename_sem);

fid = v9fs_fid_find(ds, uid, any);
if (!fid) { /* the user is not attached to the fs yet */
if (access == V9FS_ACCESS_SINGLE)
return ERR_PTR(-EPERM);
/* start from the root and try to do a lookup */
fid = v9fs_fid_find(dentry->d_sb->s_root, uid, any);
if (!fid) {
/* the user is not attached to the fs yet */
if (access == V9FS_ACCESS_SINGLE)
return ERR_PTR(-EPERM);

if (v9fs_proto_dotu(v9ses))
if (v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses))
uname = NULL;
else
uname = v9ses->uname;
else
uname = v9ses->uname;

fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
v9ses->aname);

if (IS_ERR(fid))
return fid;

v9fs_fid_add(ds, fid);
}
} else /* walk from the parent */
n = 1;
fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
v9ses->aname);
if (IS_ERR(fid))
return fid;

if (ds == dentry)
v9fs_fid_add(dentry->d_sb->s_root, fid);
}
/* If we are root ourself just return that */
if (dentry->d_sb->s_root == dentry)
return fid;

wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
if (!wnames)
return ERR_PTR(-ENOMEM);

for (d = dentry, i = (n-1); i >= 0; i--, d = d->d_parent)
wnames[i] = (char *) d->d_name.name;

/*
* Do a multipath walk with attached root.
* When walking parent we need to make sure we
* don't have a parallel rename happening
*/
down_read(&v9ses->rename_sem);
n = build_path_from_dentry(v9ses, dentry, &wnames);
if (n < 0) {
fid = ERR_PTR(n);
goto err_out;
}
clone = 1;
i = 0;
while (i < n) {
l = min(n - i, P9_MAXWELEM);
/*
* We need to hold rename lock when doing a multipath
* walk to ensure none of the patch component change
*/
fid = p9_client_walk(fid, l, &wnames[i], clone);
if (IS_ERR(fid)) {
if (old_fid) {
Expand All @@ -193,15 +234,17 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
p9_client_clunk(old_fid);
}
kfree(wnames);
return fid;
goto err_out;
}
old_fid = fid;
i += l;
clone = 0;
}

kfree(wnames);
fid_out:
v9fs_fid_add(dentry, fid);
err_out:
up_read(&v9ses->rename_sem);
return fid;
}

Expand Down
3 changes: 2 additions & 1 deletion fs/9p/v9fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
__putname(v9ses->uname);
return ERR_PTR(-ENOMEM);
}
init_rwsem(&v9ses->rename_sem);

rc = bdi_setup_and_register(&v9ses->bdi, "9p", BDI_CAP_MAP_COPY);
if (rc) {
Expand Down Expand Up @@ -278,7 +279,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;

/* for legacy mode, fall back to V9FS_ACCESS_ANY */
if (!v9fs_proto_dotu(v9ses) &&
if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {

v9ses->flags &= ~V9FS_ACCESS_MASK;
Expand Down
1 change: 1 addition & 0 deletions fs/9p/v9fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ struct v9fs_session_info {
struct p9_client *clnt; /* 9p client */
struct list_head slist; /* list of sessions registered with v9fs */
struct backing_dev_info bdi;
struct rw_semaphore rename_sem;
};

struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *,
Expand Down
1 change: 1 addition & 0 deletions fs/9p/v9fs_vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode);
void v9fs_clear_inode(struct inode *inode);
ino_t v9fs_qid2ino(struct p9_qid *qid);
void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *);
int v9fs_dir_release(struct inode *inode, struct file *filp);
int v9fs_file_open(struct inode *inode, struct file *file);
void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
Expand Down
134 changes: 118 additions & 16 deletions fs/9p/vfs_dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,29 +87,19 @@ static void p9stat_init(struct p9_wstat *stbuf)
}

/**
* v9fs_dir_readdir - read a directory
* v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
* @filp: opened file structure
* @dirent: directory structure ???
* @filldir: function to populate directory structure ???
* @buflen: Length in bytes of buffer to allocate
*
*/

static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int v9fs_alloc_rdir_buf(struct file *filp, int buflen)
{
int over;
struct p9_wstat st;
int err = 0;
struct p9_fid *fid;
int buflen;
int reclen = 0;
struct p9_rdir *rdir;
struct p9_fid *fid;
int err = 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;

/* allocate rdir on demand */
if (!fid->rdir) {
rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);

Expand All @@ -128,6 +118,36 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
spin_unlock(&filp->f_dentry->d_lock);
kfree(rdir);
}
exit:
return err;
}

/**
* 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_wstat st;
int err = 0;
struct p9_fid *fid;
int buflen;
int reclen = 0;
struct p9_rdir *rdir;

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;

err = v9fs_alloc_rdir_buf(filp, buflen);
if (err)
goto exit;
rdir = (struct p9_rdir *) fid->rdir;

err = mutex_lock_interruptible(&rdir->mutex);
Expand Down Expand Up @@ -176,6 +196,88 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
return err;
}

/**
* v9fs_dir_readdir_dotl - read a directory
* @filp: opened file structure
* @dirent: buffer to fill dirent structures
* @filldir: function to populate dirent structures
*
*/
static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
filldir_t filldir)
{
int over;
int err = 0;
struct p9_fid *fid;
int buflen;
struct p9_rdir *rdir;
struct p9_dirent curdirent;
u64 oldoffset = 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_READDIRHDRSZ;

err = v9fs_alloc_rdir_buf(filp, buflen);
if (err)
goto exit;
rdir = (struct p9_rdir *) fid->rdir;

err = mutex_lock_interruptible(&rdir->mutex);
if (err)
return err;

while (err == 0) {
if (rdir->tail == rdir->head) {
err = p9_client_readdir(fid, rdir->buf, buflen,
filp->f_pos);
if (err <= 0)
goto unlock_and_exit;

rdir->head = 0;
rdir->tail = err;
}

while (rdir->head < rdir->tail) {

err = p9dirent_read(rdir->buf + rdir->head,
buflen - rdir->head, &curdirent,
fid->clnt->proto_version);
if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
err = -EIO;
goto unlock_and_exit;
}

/* d_off in dirent structure tracks the offset into
* the next dirent in the dir. However, filldir()
* expects offset into the current dirent. Hence
* while calling filldir send the offset from the
* previous dirent structure.
*/
over = filldir(dirent, curdirent.d_name,
strlen(curdirent.d_name),
oldoffset, v9fs_qid2ino(&curdirent.qid),
curdirent.d_type);
oldoffset = curdirent.d_off;

if (over) {
err = 0;
goto unlock_and_exit;
}

filp->f_pos = curdirent.d_off;
rdir->head += err;
}
}

unlock_and_exit:
mutex_unlock(&rdir->mutex);
exit:
return err;
}


/**
* v9fs_dir_release - close a directory
Expand Down Expand Up @@ -207,7 +309,7 @@ const struct file_operations v9fs_dir_operations = {
const struct file_operations v9fs_dir_operations_dotl = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = v9fs_dir_readdir,
.readdir = v9fs_dir_readdir_dotl,
.open = v9fs_file_open,
.release = v9fs_dir_release,
};
Loading

0 comments on commit b8b3e90

Please sign in to comment.