4 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
5 * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to:
18 * Free Software Foundation
19 * 51 Franklin Street, Fifth Floor
20 * Boston, MA 02111-1301 USA
24 #include <linux/module.h>
25 #include <linux/errno.h>
27 #include <linux/sched.h>
28 #include <linux/idr.h>
29 #include <net/9p/9p.h>
30 #include <net/9p/client.h>
37 * v9fs_fid_add - add a fid to a dentry
38 * @dentry: dentry that the fid is being added to
43 int v9fs_fid_add(struct dentry
*dentry
, struct p9_fid
*fid
)
45 struct v9fs_dentry
*dent
;
47 P9_DPRINTK(P9_DEBUG_VFS
, "fid %d dentry %s\n",
48 fid
->fid
, dentry
->d_name
.name
);
50 dent
= dentry
->d_fsdata
;
52 dent
= kmalloc(sizeof(struct v9fs_dentry
), GFP_KERNEL
);
56 spin_lock_init(&dent
->lock
);
57 INIT_LIST_HEAD(&dent
->fidlist
);
58 dentry
->d_fsdata
= dent
;
61 spin_lock(&dent
->lock
);
62 list_add(&fid
->dlist
, &dent
->fidlist
);
63 spin_unlock(&dent
->lock
);
69 * v9fs_fid_find - retrieve a fid that belongs to the specified uid
70 * @dentry: dentry to look for fid in
71 * @uid: return fid that belongs to the specified user
72 * @any: if non-zero, return any fid associated with the dentry
76 static struct p9_fid
*v9fs_fid_find(struct dentry
*dentry
, u32 uid
, int any
)
78 struct v9fs_dentry
*dent
;
79 struct p9_fid
*fid
, *ret
;
81 P9_DPRINTK(P9_DEBUG_VFS
, " dentry: %s (%p) uid %d any %d\n",
82 dentry
->d_name
.name
, dentry
, uid
, any
);
83 dent
= (struct v9fs_dentry
*) dentry
->d_fsdata
;
86 spin_lock(&dent
->lock
);
87 list_for_each_entry(fid
, &dent
->fidlist
, dlist
) {
88 if (any
|| fid
->uid
== uid
) {
93 spin_unlock(&dent
->lock
);
100 * v9fs_fid_lookup - lookup for a fid, try to walk if not found
101 * @dentry: dentry to look for fid in
103 * Look for a fid in the specified dentry for the current user.
104 * If no fid is found, try to create one walking from a fid from the parent
105 * dentry (if it has one), or the root dentry. If the user haven't accessed
106 * the fs yet, attach now and walk from the root.
109 struct p9_fid
*v9fs_fid_lookup(struct dentry
*dentry
)
111 int i
, n
, l
, clone
, any
, access
;
114 struct dentry
*d
, *ds
;
115 struct v9fs_session_info
*v9ses
;
116 char **wnames
, *uname
;
118 v9ses
= v9fs_inode2v9ses(dentry
->d_inode
);
119 access
= v9ses
->flags
& V9FS_ACCESS_MASK
;
121 case V9FS_ACCESS_SINGLE
:
122 case V9FS_ACCESS_USER
:
123 uid
= current_fsuid();
127 case V9FS_ACCESS_ANY
:
138 fid
= v9fs_fid_find(dentry
, uid
, any
);
142 ds
= dentry
->d_parent
;
143 fid
= v9fs_fid_find(ds
, uid
, any
);
144 if (!fid
) { /* walk from the root */
146 for (ds
= dentry
; !IS_ROOT(ds
); ds
= ds
->d_parent
)
149 fid
= v9fs_fid_find(ds
, uid
, any
);
150 if (!fid
) { /* the user is not attached to the fs yet */
151 if (access
== V9FS_ACCESS_SINGLE
)
152 return ERR_PTR(-EPERM
);
154 if (v9fs_proto_dotu(v9ses
))
157 uname
= v9ses
->uname
;
159 fid
= p9_client_attach(v9ses
->clnt
, NULL
, uname
, uid
,
165 v9fs_fid_add(ds
, fid
);
167 } else /* walk from the parent */
173 wnames
= kmalloc(sizeof(char *) * n
, GFP_KERNEL
);
175 return ERR_PTR(-ENOMEM
);
177 for (d
= dentry
, i
= (n
-1); i
>= 0; i
--, d
= d
->d_parent
)
178 wnames
[i
] = (char *) d
->d_name
.name
;
183 l
= min(n
- i
, P9_MAXWELEM
);
184 fid
= p9_client_walk(fid
, l
, &wnames
[i
], clone
);
195 v9fs_fid_add(dentry
, fid
);
199 struct p9_fid
*v9fs_fid_clone(struct dentry
*dentry
)
201 struct p9_fid
*fid
, *ret
;
203 fid
= v9fs_fid_lookup(dentry
);
207 ret
= p9_client_walk(fid
, 0, NULL
, 1);