LINUX: consolidate duplicate code in osi_TryEvictDentries
[openafs.git] / src / afs / LINUX / osi_misc.c
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 afs_osi_SetTime(osi_timeval_t * tvp)
33 {
34     struct timespec tv;
35     tv.tv_sec = tvp->tv_sec;
36     tv.tv_nsec = tvp->tv_usec * NSEC_PER_USEC;
37
38     AFS_STATCNT(osi_SetTime);
39
40     do_settimeofday(&tv);
41 }
42
43 void
44 osi_linux_mask(void)
45 {
46     SIG_LOCK(current);
47     sigfillset(&current->blocked);
48     RECALC_SIGPENDING(current);
49     SIG_UNLOCK(current);
50 }
51
52 /* LOOKUP_POSITIVE is becoming the default */
53 #ifndef LOOKUP_POSITIVE
54 #define LOOKUP_POSITIVE 0
55 #endif
56 /* Lookup name and return vnode for same. */
57 int
58 osi_lookupname_internal(char *aname, int followlink, struct vfsmount **mnt,
59                         struct dentry **dpp)
60 {
61     int code;
62 #if defined(HAVE_LINUX_PATH_LOOKUP)
63     struct nameidata path_data;
64 #else
65     afs_linux_path_t path_data;
66 #endif
67     int flags = LOOKUP_POSITIVE;
68
69     if (followlink)
70        flags |= LOOKUP_FOLLOW;
71     code = afs_kern_path(aname, flags, &path_data);
72
73     if (!code)
74         afs_get_dentry_ref(&path_data, mnt, dpp);
75
76     return code;
77 }
78
79 static char *
80 afs_getname(char *aname)
81 {
82     int len;
83     char *name = kmem_cache_alloc(names_cachep, GFP_KERNEL);
84
85     if (!name)
86         return ERR_PTR(-ENOMEM);
87
88     len = strncpy_from_user(name, aname, PATH_MAX);
89     if (len < 0)
90         goto error;
91     if (len >= PATH_MAX) {
92         len = -ENAMETOOLONG;
93         goto error;
94     }
95     return name;
96
97 error:
98     kmem_cache_free(names_cachep, name);
99     return ERR_PTR(len);
100 }
101
102 static void
103 afs_putname(char *name)
104 {
105     kmem_cache_free(names_cachep, name);
106 }
107
108 int
109 osi_lookupname(char *aname, uio_seg_t seg, int followlink,
110                struct dentry **dpp)
111 {
112     int code;
113     char *name;
114
115     if (seg == AFS_UIOUSER) {
116         name = afs_getname(aname);
117         if (IS_ERR(name))
118             return -PTR_ERR(name);
119     } else {
120         name = aname;
121     }
122     code = osi_lookupname_internal(name, followlink, NULL, dpp);
123     if (seg == AFS_UIOUSER) {
124         afs_putname(name);
125     }
126     return code;
127 }
128
129 int osi_abspath(char *aname, char *buf, int buflen,
130                 int followlink, char **pathp)
131 {
132     struct dentry *dp = NULL;
133     struct vfsmount *mnt = NULL;
134     char *name, *path;
135     int code;
136
137     name = afs_getname(aname);
138     if (IS_ERR(name))
139         return -PTR_ERR(name);
140     code = osi_lookupname_internal(name, followlink, &mnt, &dp);
141     if (!code) {
142 #if defined(D_PATH_TAKES_STRUCT_PATH)
143         afs_linux_path_t p = { .mnt = mnt, .dentry = dp };
144         path = d_path(&p, buf, buflen);
145 #else
146         path = d_path(dp, mnt, buf, buflen);
147 #endif
148
149         if (IS_ERR(path)) {
150             code = -PTR_ERR(path);
151         } else {
152             *pathp = path;
153         }
154
155         dput(dp);
156         mntput(mnt);
157     }
158
159     afs_putname(name);
160     return code;
161 }
162
163
164 /* This could use some work, and support on more platforms. */
165 int afs_thread_wrapper(void *rock)
166 {
167     void (*proc)(void) = rock;
168     __module_get(THIS_MODULE);
169     AFS_GLOCK();
170     (*proc)();
171     AFS_GUNLOCK();
172     module_put(THIS_MODULE);
173     return 0;
174 }
175
176 void afs_start_thread(void (*proc)(void), char *name)
177 {
178     kthread_run(afs_thread_wrapper, proc, "%s", name);
179 }