Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This software has been released under the terms of the IBM Public | |
6 | * License. For details, see the LICENSE file in the top-level source | |
7 | * directory or online at http://www.openafs.org/dl/license10.html | |
8 | */ | |
9 | ||
10 | /* | |
11 | * Linux support routines. | |
12 | * | |
13 | */ | |
14 | #include <afsconfig.h> | |
15 | #include "afs/param.h" | |
16 | ||
17 | ||
18 | #include <linux/module.h> /* early to avoid printf->printk mapping */ | |
19 | #include <linux/dcache.h> | |
20 | #include <linux/namei.h> | |
21 | #include <linux/kthread.h> | |
22 | #include "afs/sysincludes.h" | |
23 | #include "afsincludes.h" | |
24 | #include "afs/afs_stats.h" | |
25 | ||
26 | #include "osi_compat.h" | |
27 | ||
28 | int afs_osicred_initialized = 0; | |
29 | afs_ucred_t afs_osi_cred; | |
30 | ||
31 | void | |
32 | osi_linux_mask(void) | |
33 | { | |
34 | SIG_LOCK(current); | |
35 | sigfillset(¤t->blocked); | |
36 | RECALC_SIGPENDING(current); | |
37 | SIG_UNLOCK(current); | |
38 | } | |
39 | ||
40 | void | |
41 | osi_linux_unmaskrxk(void) | |
42 | { | |
43 | extern struct task_struct *rxk_ListenerTask; | |
44 | /* Note this unblocks signals on the rxk_Listener | |
45 | * thread from a thread that is stopping rxk */ | |
46 | SIG_LOCK(rxk_ListenerTask); | |
47 | sigdelset(&rxk_ListenerTask->blocked, SIGKILL); | |
48 | SIG_UNLOCK(rxk_ListenerTask); | |
49 | } | |
50 | ||
51 | /* LOOKUP_POSITIVE is becoming the default */ | |
52 | #ifndef LOOKUP_POSITIVE | |
53 | #define LOOKUP_POSITIVE 0 | |
54 | #endif | |
55 | /* Lookup name and return vnode for same. */ | |
56 | int | |
57 | osi_lookupname_internal(char *aname, int followlink, struct vfsmount **mnt, | |
58 | struct dentry **dpp) | |
59 | { | |
60 | int code; | |
61 | #if defined(HAVE_LINUX_PATH_LOOKUP) | |
62 | struct nameidata path_data; | |
63 | #else | |
64 | afs_linux_path_t path_data; | |
65 | #endif | |
66 | int flags = LOOKUP_POSITIVE; | |
67 | ||
68 | if (followlink) | |
69 | flags |= LOOKUP_FOLLOW; | |
70 | code = afs_kern_path(aname, flags, &path_data); | |
71 | ||
72 | if (!code) | |
73 | afs_get_dentry_ref(&path_data, mnt, dpp); | |
74 | ||
75 | return code; | |
76 | } | |
77 | ||
78 | static char * | |
79 | afs_getname(char *aname) | |
80 | { | |
81 | int len; | |
82 | char *name = kmem_cache_alloc(names_cachep, GFP_KERNEL); | |
83 | ||
84 | if (!name) | |
85 | return ERR_PTR(-ENOMEM); | |
86 | ||
87 | len = strncpy_from_user(name, aname, PATH_MAX); | |
88 | if (len < 0) | |
89 | goto error; | |
90 | if (len >= PATH_MAX) { | |
91 | len = -ENAMETOOLONG; | |
92 | goto error; | |
93 | } | |
94 | return name; | |
95 | ||
96 | error: | |
97 | kmem_cache_free(names_cachep, name); | |
98 | return ERR_PTR(len); | |
99 | } | |
100 | ||
101 | static void | |
102 | afs_putname(char *name) | |
103 | { | |
104 | kmem_cache_free(names_cachep, name); | |
105 | } | |
106 | ||
107 | int | |
108 | osi_lookupname(char *aname, uio_seg_t seg, int followlink, | |
109 | struct dentry **dpp) | |
110 | { | |
111 | int code; | |
112 | char *name; | |
113 | ||
114 | if (seg == AFS_UIOUSER) { | |
115 | name = afs_getname(aname); | |
116 | if (IS_ERR(name)) | |
117 | return -PTR_ERR(name); | |
118 | } else { | |
119 | name = aname; | |
120 | } | |
121 | code = osi_lookupname_internal(name, followlink, NULL, dpp); | |
122 | if (seg == AFS_UIOUSER) { | |
123 | afs_putname(name); | |
124 | } | |
125 | return code; | |
126 | } | |
127 | ||
128 | int osi_abspath(char *aname, char *buf, int buflen, | |
129 | int followlink, char **pathp) | |
130 | { | |
131 | struct dentry *dp = NULL; | |
132 | struct vfsmount *mnt = NULL; | |
133 | char *name, *path; | |
134 | int code; | |
135 | ||
136 | name = afs_getname(aname); | |
137 | if (IS_ERR(name)) | |
138 | return -PTR_ERR(name); | |
139 | code = osi_lookupname_internal(name, followlink, &mnt, &dp); | |
140 | if (!code) { | |
141 | #if defined(D_PATH_TAKES_STRUCT_PATH) | |
142 | afs_linux_path_t p = { .mnt = mnt, .dentry = dp }; | |
143 | path = d_path(&p, buf, buflen); | |
144 | #else | |
145 | path = d_path(dp, mnt, buf, buflen); | |
146 | #endif | |
147 | ||
148 | if (IS_ERR(path)) { | |
149 | code = -PTR_ERR(path); | |
150 | } else { | |
151 | *pathp = path; | |
152 | } | |
153 | ||
154 | dput(dp); | |
155 | mntput(mnt); | |
156 | } | |
157 | ||
158 | afs_putname(name); | |
159 | return code; | |
160 | } | |
161 | ||
162 | ||
163 | /* This could use some work, and support on more platforms. */ | |
164 | int afs_thread_wrapper(void *rock) | |
165 | { | |
166 | void (*proc)(void) = rock; | |
167 | __module_get(THIS_MODULE); | |
168 | AFS_GLOCK(); | |
169 | (*proc)(); | |
170 | AFS_GUNLOCK(); | |
171 | module_put(THIS_MODULE); | |
172 | return 0; | |
173 | } | |
174 | ||
175 | void afs_start_thread(void (*proc)(void), char *name) | |
176 | { | |
177 | kthread_run(afs_thread_wrapper, proc, "%s", name); | |
178 | } |