08fa320b7e6d20deedb124a1ea549c79ba4e597a
[safe/jmp/linux-2.6] / fs / 9p / fid.c
1 /*
2  * V9FS FID Management
3  *
4  *  Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License version 2
8  *  as published by the Free Software Foundation.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to:
17  *  Free Software Foundation
18  *  51 Franklin Street, Fifth Floor
19  *  Boston, MA  02111-1301  USA
20  *
21  */
22
23 #include <linux/module.h>
24 #include <linux/errno.h>
25 #include <linux/fs.h>
26 #include <linux/sched.h>
27 #include <linux/idr.h>
28 #include <asm/semaphore.h>
29 #include <net/9p/9p.h>
30 #include <net/9p/client.h>
31
32 #include "v9fs.h"
33 #include "v9fs_vfs.h"
34 #include "fid.h"
35
36 /**
37  * v9fs_fid_insert - add a fid to a dentry
38  * @fid: fid to add
39  * @dentry: dentry that it is being added to
40  *
41  */
42
43 int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
44 {
45         struct v9fs_dentry *dent;
46
47         P9_DPRINTK(P9_DEBUG_VFS, "fid %d dentry %s\n",
48                                         fid->fid, dentry->d_iname);
49
50         dent = dentry->d_fsdata;
51         if (!dent) {
52                 dent = kmalloc(sizeof(struct v9fs_dentry), GFP_KERNEL);
53                 if (!dent)
54                         return -ENOMEM;
55
56                 spin_lock_init(&dent->lock);
57                 INIT_LIST_HEAD(&dent->fidlist);
58                 dentry->d_fsdata = dent;
59         }
60
61         spin_lock(&dent->lock);
62         list_add(&fid->dlist, &dent->fidlist);
63         spin_unlock(&dent->lock);
64
65         return 0;
66 }
67
68 /**
69  * v9fs_fid_lookup - return a locked fid from a dentry
70  * @dentry: dentry to look for fid in
71  *
72  * find a fid in the dentry, obtain its semaphore and return a reference to it.
73  * code calling lookup is responsible for releasing lock
74  *
75  * TODO: only match fids that have the same uid as current user
76  *
77  */
78
79 struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
80 {
81         struct v9fs_dentry *dent;
82         struct p9_fid *fid;
83
84         P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
85         dent = dentry->d_fsdata;
86         if (dent)
87                 fid = list_entry(dent->fidlist.next, struct p9_fid, dlist);
88         else
89                 fid = ERR_PTR(-EBADF);
90
91         P9_DPRINTK(P9_DEBUG_VFS, " fid: %p\n", fid);
92         return fid;
93 }
94
95 struct p9_fid *v9fs_fid_lookup_remove(struct dentry *dentry)
96 {
97         struct p9_fid *fid;
98         struct v9fs_dentry *dent;
99
100         dent = dentry->d_fsdata;
101         fid = v9fs_fid_lookup(dentry);
102         if (!IS_ERR(fid)) {
103                 spin_lock(&dent->lock);
104                 list_del(&fid->dlist);
105                 spin_unlock(&dent->lock);
106         }
107
108         return fid;
109 }
110
111
112 /**
113  * v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and
114  *      release it
115  * @dentry: dentry to look for fid in
116  *
117  * find a fid in the dentry and then clone to a new private fid
118  *
119  * TODO: only match fids that have the same uid as current user
120  *
121  */
122
123 struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
124 {
125         struct p9_fid *ofid, *fid;
126
127         P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
128         ofid = v9fs_fid_lookup(dentry);
129         if (IS_ERR(ofid))
130                 return ofid;
131
132         fid = p9_client_walk(ofid, 0, NULL, 1);
133         return fid;
134 }