]>
git.ipfire.org Git - people/ms/linux.git/blob - fs/9p/fid.c
1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
6 * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com>
9 #include <linux/module.h>
10 #include <linux/errno.h>
12 #include <linux/slab.h>
13 #include <linux/sched.h>
14 #include <linux/idr.h>
15 #include <net/9p/9p.h>
16 #include <net/9p/client.h>
22 static inline void __add_fid(struct dentry
*dentry
, struct p9_fid
*fid
)
24 hlist_add_head(&fid
->dlist
, (struct hlist_head
*)&dentry
->d_fsdata
);
29 * v9fs_fid_add - add a fid to a dentry
30 * @dentry: dentry that the fid is being added to
31 * @pfid: fid to add, NULLed out
34 void v9fs_fid_add(struct dentry
*dentry
, struct p9_fid
**pfid
)
36 struct p9_fid
*fid
= *pfid
;
38 spin_lock(&dentry
->d_lock
);
39 __add_fid(dentry
, fid
);
40 spin_unlock(&dentry
->d_lock
);
46 * v9fs_fid_find_inode - search for an open fid off of the inode list
47 * @inode: return a fid pointing to a specific inode
48 * @uid: return a fid belonging to the specified user
52 static struct p9_fid
*v9fs_fid_find_inode(struct inode
*inode
, kuid_t uid
)
55 struct p9_fid
*fid
, *ret
= NULL
;
57 p9_debug(P9_DEBUG_VFS
, " inode: %p\n", inode
);
59 spin_lock(&inode
->i_lock
);
60 h
= (struct hlist_head
*)&inode
->i_private
;
61 hlist_for_each_entry(fid
, h
, ilist
) {
62 if (uid_eq(fid
->uid
, uid
)) {
68 spin_unlock(&inode
->i_lock
);
73 * v9fs_open_fid_add - add an open fid to an inode
74 * @inode: inode that the fid is being added to
75 * @pfid: fid to add, NULLed out
79 void v9fs_open_fid_add(struct inode
*inode
, struct p9_fid
**pfid
)
81 struct p9_fid
*fid
= *pfid
;
83 spin_lock(&inode
->i_lock
);
84 hlist_add_head(&fid
->ilist
, (struct hlist_head
*)&inode
->i_private
);
85 spin_unlock(&inode
->i_lock
);
92 * v9fs_fid_find - retrieve a fid that belongs to the specified uid
93 * @dentry: dentry to look for fid in
94 * @uid: return fid that belongs to the specified user
95 * @any: if non-zero, return any fid associated with the dentry
99 static struct p9_fid
*v9fs_fid_find(struct dentry
*dentry
, kuid_t uid
, int any
)
101 struct p9_fid
*fid
, *ret
;
103 p9_debug(P9_DEBUG_VFS
, " dentry: %pd (%p) uid %d any %d\n",
104 dentry
, dentry
, from_kuid(&init_user_ns
, uid
),
107 /* we'll recheck under lock if there's anything to look in */
108 if (dentry
->d_fsdata
) {
109 struct hlist_head
*h
= (struct hlist_head
*)&dentry
->d_fsdata
;
111 spin_lock(&dentry
->d_lock
);
112 hlist_for_each_entry(fid
, h
, dlist
) {
113 if (any
|| uid_eq(fid
->uid
, uid
)) {
119 spin_unlock(&dentry
->d_lock
);
122 ret
= v9fs_fid_find_inode(dentry
->d_inode
, uid
);
129 * We need to hold v9ses->rename_sem as long as we hold references
130 * to returned path array. Array element contain pointers to
133 static int build_path_from_dentry(struct v9fs_session_info
*v9ses
,
134 struct dentry
*dentry
, const unsigned char ***names
)
137 const unsigned char **wnames
;
140 for (ds
= dentry
; !IS_ROOT(ds
); ds
= ds
->d_parent
)
143 wnames
= kmalloc_array(n
, sizeof(char *), GFP_KERNEL
);
147 for (ds
= dentry
, i
= (n
-1); i
>= 0; i
--, ds
= ds
->d_parent
)
148 wnames
[i
] = ds
->d_name
.name
;
156 static struct p9_fid
*v9fs_fid_lookup_with_uid(struct dentry
*dentry
,
160 const unsigned char **wnames
, *uname
;
162 struct v9fs_session_info
*v9ses
;
163 struct p9_fid
*fid
, *root_fid
, *old_fid
;
165 v9ses
= v9fs_dentry2v9ses(dentry
);
166 access
= v9ses
->flags
& V9FS_ACCESS_MASK
;
167 fid
= v9fs_fid_find(dentry
, uid
, any
);
171 * we don't have a matching fid. To do a TWALK we need
172 * parent fid. We need to prevent rename when we want to
173 * look at the parent.
175 down_read(&v9ses
->rename_sem
);
176 ds
= dentry
->d_parent
;
177 fid
= v9fs_fid_find(ds
, uid
, any
);
179 /* Found the parent fid do a lookup with that */
182 fid
= p9_client_walk(old_fid
, 1, &dentry
->d_name
.name
, 1);
186 up_read(&v9ses
->rename_sem
);
188 /* start from the root and try to do a lookup */
189 root_fid
= v9fs_fid_find(dentry
->d_sb
->s_root
, uid
, any
);
191 /* the user is not attached to the fs yet */
192 if (access
== V9FS_ACCESS_SINGLE
)
193 return ERR_PTR(-EPERM
);
195 if (v9fs_proto_dotu(v9ses
) || v9fs_proto_dotl(v9ses
))
198 uname
= v9ses
->uname
;
200 fid
= p9_client_attach(v9ses
->clnt
, NULL
, uname
, uid
,
205 root_fid
= p9_fid_get(fid
);
206 v9fs_fid_add(dentry
->d_sb
->s_root
, &fid
);
208 /* If we are root ourself just return that */
209 if (dentry
->d_sb
->s_root
== dentry
)
213 * Do a multipath walk with attached root.
214 * When walking parent we need to make sure we
215 * don't have a parallel rename happening
217 down_read(&v9ses
->rename_sem
);
218 n
= build_path_from_dentry(v9ses
, dentry
, &wnames
);
227 l
= min(n
- i
, P9_MAXWELEM
);
229 * We need to hold rename lock when doing a multipath
230 * walk to ensure none of the path components change
232 fid
= p9_client_walk(old_fid
, l
, &wnames
[i
],
233 old_fid
== root_fid
/* clone */);
234 /* non-cloning walk will return the same fid */
235 if (fid
!= old_fid
) {
248 spin_lock(&dentry
->d_lock
);
249 if (d_unhashed(dentry
)) {
250 spin_unlock(&dentry
->d_lock
);
252 fid
= ERR_PTR(-ENOENT
);
254 __add_fid(dentry
, fid
);
256 spin_unlock(&dentry
->d_lock
);
260 up_read(&v9ses
->rename_sem
);
265 * v9fs_fid_lookup - lookup for a fid, try to walk if not found
266 * @dentry: dentry to look for fid in
268 * Look for a fid in the specified dentry for the current user.
269 * If no fid is found, try to create one walking from a fid from the parent
270 * dentry (if it has one), or the root dentry. If the user haven't accessed
271 * the fs yet, attach now and walk from the root.
274 struct p9_fid
*v9fs_fid_lookup(struct dentry
*dentry
)
278 struct v9fs_session_info
*v9ses
;
280 v9ses
= v9fs_dentry2v9ses(dentry
);
281 access
= v9ses
->flags
& V9FS_ACCESS_MASK
;
283 case V9FS_ACCESS_SINGLE
:
284 case V9FS_ACCESS_USER
:
285 case V9FS_ACCESS_CLIENT
:
286 uid
= current_fsuid();
290 case V9FS_ACCESS_ANY
:
300 return v9fs_fid_lookup_with_uid(dentry
, uid
, any
);
303 struct p9_fid
*v9fs_writeback_fid(struct dentry
*dentry
)
306 struct p9_fid
*fid
, *ofid
;
308 ofid
= v9fs_fid_lookup_with_uid(dentry
, GLOBAL_ROOT_UID
, 0);
309 fid
= clone_fid(ofid
);
314 * writeback fid will only be used to write back the
315 * dirty pages. We always request for the open fid in read-write
316 * mode so that a partial page write which result in page
319 err
= p9_client_open(fid
, O_RDWR
);