Commit 542ce7a9bc6b3838832ae0f4f8de30c667af8ff3
Committed by
Al Viro
1 parent
6d0b5456e1
Exists in
master
and in
7 other branches
cachefiles: use path_get instead of lone dget
Dentry references should not be acquired without a corresponding vfsmount ref. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 1 changed file with 14 additions and 12 deletions Inline Diff
fs/cachefiles/daemon.c
1 | /* Daemon interface | 1 | /* Daemon interface |
2 | * | 2 | * |
3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public Licence | 7 | * modify it under the terms of the GNU General Public Licence |
8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/completion.h> | 15 | #include <linux/completion.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/file.h> | 18 | #include <linux/file.h> |
19 | #include <linux/namei.h> | 19 | #include <linux/namei.h> |
20 | #include <linux/poll.h> | 20 | #include <linux/poll.h> |
21 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
22 | #include <linux/statfs.h> | 22 | #include <linux/statfs.h> |
23 | #include <linux/ctype.h> | 23 | #include <linux/ctype.h> |
24 | #include <linux/string.h> | 24 | #include <linux/string.h> |
25 | #include <linux/fs_struct.h> | 25 | #include <linux/fs_struct.h> |
26 | #include "internal.h" | 26 | #include "internal.h" |
27 | 27 | ||
28 | static int cachefiles_daemon_open(struct inode *, struct file *); | 28 | static int cachefiles_daemon_open(struct inode *, struct file *); |
29 | static int cachefiles_daemon_release(struct inode *, struct file *); | 29 | static int cachefiles_daemon_release(struct inode *, struct file *); |
30 | static ssize_t cachefiles_daemon_read(struct file *, char __user *, size_t, | 30 | static ssize_t cachefiles_daemon_read(struct file *, char __user *, size_t, |
31 | loff_t *); | 31 | loff_t *); |
32 | static ssize_t cachefiles_daemon_write(struct file *, const char __user *, | 32 | static ssize_t cachefiles_daemon_write(struct file *, const char __user *, |
33 | size_t, loff_t *); | 33 | size_t, loff_t *); |
34 | static unsigned int cachefiles_daemon_poll(struct file *, | 34 | static unsigned int cachefiles_daemon_poll(struct file *, |
35 | struct poll_table_struct *); | 35 | struct poll_table_struct *); |
36 | static int cachefiles_daemon_frun(struct cachefiles_cache *, char *); | 36 | static int cachefiles_daemon_frun(struct cachefiles_cache *, char *); |
37 | static int cachefiles_daemon_fcull(struct cachefiles_cache *, char *); | 37 | static int cachefiles_daemon_fcull(struct cachefiles_cache *, char *); |
38 | static int cachefiles_daemon_fstop(struct cachefiles_cache *, char *); | 38 | static int cachefiles_daemon_fstop(struct cachefiles_cache *, char *); |
39 | static int cachefiles_daemon_brun(struct cachefiles_cache *, char *); | 39 | static int cachefiles_daemon_brun(struct cachefiles_cache *, char *); |
40 | static int cachefiles_daemon_bcull(struct cachefiles_cache *, char *); | 40 | static int cachefiles_daemon_bcull(struct cachefiles_cache *, char *); |
41 | static int cachefiles_daemon_bstop(struct cachefiles_cache *, char *); | 41 | static int cachefiles_daemon_bstop(struct cachefiles_cache *, char *); |
42 | static int cachefiles_daemon_cull(struct cachefiles_cache *, char *); | 42 | static int cachefiles_daemon_cull(struct cachefiles_cache *, char *); |
43 | static int cachefiles_daemon_debug(struct cachefiles_cache *, char *); | 43 | static int cachefiles_daemon_debug(struct cachefiles_cache *, char *); |
44 | static int cachefiles_daemon_dir(struct cachefiles_cache *, char *); | 44 | static int cachefiles_daemon_dir(struct cachefiles_cache *, char *); |
45 | static int cachefiles_daemon_inuse(struct cachefiles_cache *, char *); | 45 | static int cachefiles_daemon_inuse(struct cachefiles_cache *, char *); |
46 | static int cachefiles_daemon_secctx(struct cachefiles_cache *, char *); | 46 | static int cachefiles_daemon_secctx(struct cachefiles_cache *, char *); |
47 | static int cachefiles_daemon_tag(struct cachefiles_cache *, char *); | 47 | static int cachefiles_daemon_tag(struct cachefiles_cache *, char *); |
48 | 48 | ||
49 | static unsigned long cachefiles_open; | 49 | static unsigned long cachefiles_open; |
50 | 50 | ||
51 | const struct file_operations cachefiles_daemon_fops = { | 51 | const struct file_operations cachefiles_daemon_fops = { |
52 | .owner = THIS_MODULE, | 52 | .owner = THIS_MODULE, |
53 | .open = cachefiles_daemon_open, | 53 | .open = cachefiles_daemon_open, |
54 | .release = cachefiles_daemon_release, | 54 | .release = cachefiles_daemon_release, |
55 | .read = cachefiles_daemon_read, | 55 | .read = cachefiles_daemon_read, |
56 | .write = cachefiles_daemon_write, | 56 | .write = cachefiles_daemon_write, |
57 | .poll = cachefiles_daemon_poll, | 57 | .poll = cachefiles_daemon_poll, |
58 | }; | 58 | }; |
59 | 59 | ||
60 | struct cachefiles_daemon_cmd { | 60 | struct cachefiles_daemon_cmd { |
61 | char name[8]; | 61 | char name[8]; |
62 | int (*handler)(struct cachefiles_cache *cache, char *args); | 62 | int (*handler)(struct cachefiles_cache *cache, char *args); |
63 | }; | 63 | }; |
64 | 64 | ||
65 | static const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = { | 65 | static const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = { |
66 | { "bind", cachefiles_daemon_bind }, | 66 | { "bind", cachefiles_daemon_bind }, |
67 | { "brun", cachefiles_daemon_brun }, | 67 | { "brun", cachefiles_daemon_brun }, |
68 | { "bcull", cachefiles_daemon_bcull }, | 68 | { "bcull", cachefiles_daemon_bcull }, |
69 | { "bstop", cachefiles_daemon_bstop }, | 69 | { "bstop", cachefiles_daemon_bstop }, |
70 | { "cull", cachefiles_daemon_cull }, | 70 | { "cull", cachefiles_daemon_cull }, |
71 | { "debug", cachefiles_daemon_debug }, | 71 | { "debug", cachefiles_daemon_debug }, |
72 | { "dir", cachefiles_daemon_dir }, | 72 | { "dir", cachefiles_daemon_dir }, |
73 | { "frun", cachefiles_daemon_frun }, | 73 | { "frun", cachefiles_daemon_frun }, |
74 | { "fcull", cachefiles_daemon_fcull }, | 74 | { "fcull", cachefiles_daemon_fcull }, |
75 | { "fstop", cachefiles_daemon_fstop }, | 75 | { "fstop", cachefiles_daemon_fstop }, |
76 | { "inuse", cachefiles_daemon_inuse }, | 76 | { "inuse", cachefiles_daemon_inuse }, |
77 | { "secctx", cachefiles_daemon_secctx }, | 77 | { "secctx", cachefiles_daemon_secctx }, |
78 | { "tag", cachefiles_daemon_tag }, | 78 | { "tag", cachefiles_daemon_tag }, |
79 | { "", NULL } | 79 | { "", NULL } |
80 | }; | 80 | }; |
81 | 81 | ||
82 | 82 | ||
83 | /* | 83 | /* |
84 | * do various checks | 84 | * do various checks |
85 | */ | 85 | */ |
86 | static int cachefiles_daemon_open(struct inode *inode, struct file *file) | 86 | static int cachefiles_daemon_open(struct inode *inode, struct file *file) |
87 | { | 87 | { |
88 | struct cachefiles_cache *cache; | 88 | struct cachefiles_cache *cache; |
89 | 89 | ||
90 | _enter(""); | 90 | _enter(""); |
91 | 91 | ||
92 | /* only the superuser may do this */ | 92 | /* only the superuser may do this */ |
93 | if (!capable(CAP_SYS_ADMIN)) | 93 | if (!capable(CAP_SYS_ADMIN)) |
94 | return -EPERM; | 94 | return -EPERM; |
95 | 95 | ||
96 | /* the cachefiles device may only be open once at a time */ | 96 | /* the cachefiles device may only be open once at a time */ |
97 | if (xchg(&cachefiles_open, 1) == 1) | 97 | if (xchg(&cachefiles_open, 1) == 1) |
98 | return -EBUSY; | 98 | return -EBUSY; |
99 | 99 | ||
100 | /* allocate a cache record */ | 100 | /* allocate a cache record */ |
101 | cache = kzalloc(sizeof(struct cachefiles_cache), GFP_KERNEL); | 101 | cache = kzalloc(sizeof(struct cachefiles_cache), GFP_KERNEL); |
102 | if (!cache) { | 102 | if (!cache) { |
103 | cachefiles_open = 0; | 103 | cachefiles_open = 0; |
104 | return -ENOMEM; | 104 | return -ENOMEM; |
105 | } | 105 | } |
106 | 106 | ||
107 | mutex_init(&cache->daemon_mutex); | 107 | mutex_init(&cache->daemon_mutex); |
108 | cache->active_nodes = RB_ROOT; | 108 | cache->active_nodes = RB_ROOT; |
109 | rwlock_init(&cache->active_lock); | 109 | rwlock_init(&cache->active_lock); |
110 | init_waitqueue_head(&cache->daemon_pollwq); | 110 | init_waitqueue_head(&cache->daemon_pollwq); |
111 | 111 | ||
112 | /* set default caching limits | 112 | /* set default caching limits |
113 | * - limit at 1% free space and/or free files | 113 | * - limit at 1% free space and/or free files |
114 | * - cull below 5% free space and/or free files | 114 | * - cull below 5% free space and/or free files |
115 | * - cease culling above 7% free space and/or free files | 115 | * - cease culling above 7% free space and/or free files |
116 | */ | 116 | */ |
117 | cache->frun_percent = 7; | 117 | cache->frun_percent = 7; |
118 | cache->fcull_percent = 5; | 118 | cache->fcull_percent = 5; |
119 | cache->fstop_percent = 1; | 119 | cache->fstop_percent = 1; |
120 | cache->brun_percent = 7; | 120 | cache->brun_percent = 7; |
121 | cache->bcull_percent = 5; | 121 | cache->bcull_percent = 5; |
122 | cache->bstop_percent = 1; | 122 | cache->bstop_percent = 1; |
123 | 123 | ||
124 | file->private_data = cache; | 124 | file->private_data = cache; |
125 | cache->cachefilesd = file; | 125 | cache->cachefilesd = file; |
126 | return 0; | 126 | return 0; |
127 | } | 127 | } |
128 | 128 | ||
129 | /* | 129 | /* |
130 | * release a cache | 130 | * release a cache |
131 | */ | 131 | */ |
132 | static int cachefiles_daemon_release(struct inode *inode, struct file *file) | 132 | static int cachefiles_daemon_release(struct inode *inode, struct file *file) |
133 | { | 133 | { |
134 | struct cachefiles_cache *cache = file->private_data; | 134 | struct cachefiles_cache *cache = file->private_data; |
135 | 135 | ||
136 | _enter(""); | 136 | _enter(""); |
137 | 137 | ||
138 | ASSERT(cache); | 138 | ASSERT(cache); |
139 | 139 | ||
140 | set_bit(CACHEFILES_DEAD, &cache->flags); | 140 | set_bit(CACHEFILES_DEAD, &cache->flags); |
141 | 141 | ||
142 | cachefiles_daemon_unbind(cache); | 142 | cachefiles_daemon_unbind(cache); |
143 | 143 | ||
144 | ASSERT(!cache->active_nodes.rb_node); | 144 | ASSERT(!cache->active_nodes.rb_node); |
145 | 145 | ||
146 | /* clean up the control file interface */ | 146 | /* clean up the control file interface */ |
147 | cache->cachefilesd = NULL; | 147 | cache->cachefilesd = NULL; |
148 | file->private_data = NULL; | 148 | file->private_data = NULL; |
149 | cachefiles_open = 0; | 149 | cachefiles_open = 0; |
150 | 150 | ||
151 | kfree(cache); | 151 | kfree(cache); |
152 | 152 | ||
153 | _leave(""); | 153 | _leave(""); |
154 | return 0; | 154 | return 0; |
155 | } | 155 | } |
156 | 156 | ||
157 | /* | 157 | /* |
158 | * read the cache state | 158 | * read the cache state |
159 | */ | 159 | */ |
160 | static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer, | 160 | static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer, |
161 | size_t buflen, loff_t *pos) | 161 | size_t buflen, loff_t *pos) |
162 | { | 162 | { |
163 | struct cachefiles_cache *cache = file->private_data; | 163 | struct cachefiles_cache *cache = file->private_data; |
164 | char buffer[256]; | 164 | char buffer[256]; |
165 | int n; | 165 | int n; |
166 | 166 | ||
167 | //_enter(",,%zu,", buflen); | 167 | //_enter(",,%zu,", buflen); |
168 | 168 | ||
169 | if (!test_bit(CACHEFILES_READY, &cache->flags)) | 169 | if (!test_bit(CACHEFILES_READY, &cache->flags)) |
170 | return 0; | 170 | return 0; |
171 | 171 | ||
172 | /* check how much space the cache has */ | 172 | /* check how much space the cache has */ |
173 | cachefiles_has_space(cache, 0, 0); | 173 | cachefiles_has_space(cache, 0, 0); |
174 | 174 | ||
175 | /* summarise */ | 175 | /* summarise */ |
176 | clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags); | 176 | clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags); |
177 | 177 | ||
178 | n = snprintf(buffer, sizeof(buffer), | 178 | n = snprintf(buffer, sizeof(buffer), |
179 | "cull=%c" | 179 | "cull=%c" |
180 | " frun=%llx" | 180 | " frun=%llx" |
181 | " fcull=%llx" | 181 | " fcull=%llx" |
182 | " fstop=%llx" | 182 | " fstop=%llx" |
183 | " brun=%llx" | 183 | " brun=%llx" |
184 | " bcull=%llx" | 184 | " bcull=%llx" |
185 | " bstop=%llx", | 185 | " bstop=%llx", |
186 | test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0', | 186 | test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0', |
187 | (unsigned long long) cache->frun, | 187 | (unsigned long long) cache->frun, |
188 | (unsigned long long) cache->fcull, | 188 | (unsigned long long) cache->fcull, |
189 | (unsigned long long) cache->fstop, | 189 | (unsigned long long) cache->fstop, |
190 | (unsigned long long) cache->brun, | 190 | (unsigned long long) cache->brun, |
191 | (unsigned long long) cache->bcull, | 191 | (unsigned long long) cache->bcull, |
192 | (unsigned long long) cache->bstop | 192 | (unsigned long long) cache->bstop |
193 | ); | 193 | ); |
194 | 194 | ||
195 | if (n > buflen) | 195 | if (n > buflen) |
196 | return -EMSGSIZE; | 196 | return -EMSGSIZE; |
197 | 197 | ||
198 | if (copy_to_user(_buffer, buffer, n) != 0) | 198 | if (copy_to_user(_buffer, buffer, n) != 0) |
199 | return -EFAULT; | 199 | return -EFAULT; |
200 | 200 | ||
201 | return n; | 201 | return n; |
202 | } | 202 | } |
203 | 203 | ||
204 | /* | 204 | /* |
205 | * command the cache | 205 | * command the cache |
206 | */ | 206 | */ |
207 | static ssize_t cachefiles_daemon_write(struct file *file, | 207 | static ssize_t cachefiles_daemon_write(struct file *file, |
208 | const char __user *_data, | 208 | const char __user *_data, |
209 | size_t datalen, | 209 | size_t datalen, |
210 | loff_t *pos) | 210 | loff_t *pos) |
211 | { | 211 | { |
212 | const struct cachefiles_daemon_cmd *cmd; | 212 | const struct cachefiles_daemon_cmd *cmd; |
213 | struct cachefiles_cache *cache = file->private_data; | 213 | struct cachefiles_cache *cache = file->private_data; |
214 | ssize_t ret; | 214 | ssize_t ret; |
215 | char *data, *args, *cp; | 215 | char *data, *args, *cp; |
216 | 216 | ||
217 | //_enter(",,%zu,", datalen); | 217 | //_enter(",,%zu,", datalen); |
218 | 218 | ||
219 | ASSERT(cache); | 219 | ASSERT(cache); |
220 | 220 | ||
221 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) | 221 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) |
222 | return -EIO; | 222 | return -EIO; |
223 | 223 | ||
224 | if (datalen < 0 || datalen > PAGE_SIZE - 1) | 224 | if (datalen < 0 || datalen > PAGE_SIZE - 1) |
225 | return -EOPNOTSUPP; | 225 | return -EOPNOTSUPP; |
226 | 226 | ||
227 | /* drag the command string into the kernel so we can parse it */ | 227 | /* drag the command string into the kernel so we can parse it */ |
228 | data = kmalloc(datalen + 1, GFP_KERNEL); | 228 | data = kmalloc(datalen + 1, GFP_KERNEL); |
229 | if (!data) | 229 | if (!data) |
230 | return -ENOMEM; | 230 | return -ENOMEM; |
231 | 231 | ||
232 | ret = -EFAULT; | 232 | ret = -EFAULT; |
233 | if (copy_from_user(data, _data, datalen) != 0) | 233 | if (copy_from_user(data, _data, datalen) != 0) |
234 | goto error; | 234 | goto error; |
235 | 235 | ||
236 | data[datalen] = '\0'; | 236 | data[datalen] = '\0'; |
237 | 237 | ||
238 | ret = -EINVAL; | 238 | ret = -EINVAL; |
239 | if (memchr(data, '\0', datalen)) | 239 | if (memchr(data, '\0', datalen)) |
240 | goto error; | 240 | goto error; |
241 | 241 | ||
242 | /* strip any newline */ | 242 | /* strip any newline */ |
243 | cp = memchr(data, '\n', datalen); | 243 | cp = memchr(data, '\n', datalen); |
244 | if (cp) { | 244 | if (cp) { |
245 | if (cp == data) | 245 | if (cp == data) |
246 | goto error; | 246 | goto error; |
247 | 247 | ||
248 | *cp = '\0'; | 248 | *cp = '\0'; |
249 | } | 249 | } |
250 | 250 | ||
251 | /* parse the command */ | 251 | /* parse the command */ |
252 | ret = -EOPNOTSUPP; | 252 | ret = -EOPNOTSUPP; |
253 | 253 | ||
254 | for (args = data; *args; args++) | 254 | for (args = data; *args; args++) |
255 | if (isspace(*args)) | 255 | if (isspace(*args)) |
256 | break; | 256 | break; |
257 | if (*args) { | 257 | if (*args) { |
258 | if (args == data) | 258 | if (args == data) |
259 | goto error; | 259 | goto error; |
260 | *args = '\0'; | 260 | *args = '\0'; |
261 | args = skip_spaces(++args); | 261 | args = skip_spaces(++args); |
262 | } | 262 | } |
263 | 263 | ||
264 | /* run the appropriate command handler */ | 264 | /* run the appropriate command handler */ |
265 | for (cmd = cachefiles_daemon_cmds; cmd->name[0]; cmd++) | 265 | for (cmd = cachefiles_daemon_cmds; cmd->name[0]; cmd++) |
266 | if (strcmp(cmd->name, data) == 0) | 266 | if (strcmp(cmd->name, data) == 0) |
267 | goto found_command; | 267 | goto found_command; |
268 | 268 | ||
269 | error: | 269 | error: |
270 | kfree(data); | 270 | kfree(data); |
271 | //_leave(" = %zd", ret); | 271 | //_leave(" = %zd", ret); |
272 | return ret; | 272 | return ret; |
273 | 273 | ||
274 | found_command: | 274 | found_command: |
275 | mutex_lock(&cache->daemon_mutex); | 275 | mutex_lock(&cache->daemon_mutex); |
276 | 276 | ||
277 | ret = -EIO; | 277 | ret = -EIO; |
278 | if (!test_bit(CACHEFILES_DEAD, &cache->flags)) | 278 | if (!test_bit(CACHEFILES_DEAD, &cache->flags)) |
279 | ret = cmd->handler(cache, args); | 279 | ret = cmd->handler(cache, args); |
280 | 280 | ||
281 | mutex_unlock(&cache->daemon_mutex); | 281 | mutex_unlock(&cache->daemon_mutex); |
282 | 282 | ||
283 | if (ret == 0) | 283 | if (ret == 0) |
284 | ret = datalen; | 284 | ret = datalen; |
285 | goto error; | 285 | goto error; |
286 | } | 286 | } |
287 | 287 | ||
288 | /* | 288 | /* |
289 | * poll for culling state | 289 | * poll for culling state |
290 | * - use POLLOUT to indicate culling state | 290 | * - use POLLOUT to indicate culling state |
291 | */ | 291 | */ |
292 | static unsigned int cachefiles_daemon_poll(struct file *file, | 292 | static unsigned int cachefiles_daemon_poll(struct file *file, |
293 | struct poll_table_struct *poll) | 293 | struct poll_table_struct *poll) |
294 | { | 294 | { |
295 | struct cachefiles_cache *cache = file->private_data; | 295 | struct cachefiles_cache *cache = file->private_data; |
296 | unsigned int mask; | 296 | unsigned int mask; |
297 | 297 | ||
298 | poll_wait(file, &cache->daemon_pollwq, poll); | 298 | poll_wait(file, &cache->daemon_pollwq, poll); |
299 | mask = 0; | 299 | mask = 0; |
300 | 300 | ||
301 | if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags)) | 301 | if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags)) |
302 | mask |= POLLIN; | 302 | mask |= POLLIN; |
303 | 303 | ||
304 | if (test_bit(CACHEFILES_CULLING, &cache->flags)) | 304 | if (test_bit(CACHEFILES_CULLING, &cache->flags)) |
305 | mask |= POLLOUT; | 305 | mask |= POLLOUT; |
306 | 306 | ||
307 | return mask; | 307 | return mask; |
308 | } | 308 | } |
309 | 309 | ||
310 | /* | 310 | /* |
311 | * give a range error for cache space constraints | 311 | * give a range error for cache space constraints |
312 | * - can be tail-called | 312 | * - can be tail-called |
313 | */ | 313 | */ |
314 | static int cachefiles_daemon_range_error(struct cachefiles_cache *cache, | 314 | static int cachefiles_daemon_range_error(struct cachefiles_cache *cache, |
315 | char *args) | 315 | char *args) |
316 | { | 316 | { |
317 | kerror("Free space limits must be in range" | 317 | kerror("Free space limits must be in range" |
318 | " 0%%<=stop<cull<run<100%%"); | 318 | " 0%%<=stop<cull<run<100%%"); |
319 | 319 | ||
320 | return -EINVAL; | 320 | return -EINVAL; |
321 | } | 321 | } |
322 | 322 | ||
323 | /* | 323 | /* |
324 | * set the percentage of files at which to stop culling | 324 | * set the percentage of files at which to stop culling |
325 | * - command: "frun <N>%" | 325 | * - command: "frun <N>%" |
326 | */ | 326 | */ |
327 | static int cachefiles_daemon_frun(struct cachefiles_cache *cache, char *args) | 327 | static int cachefiles_daemon_frun(struct cachefiles_cache *cache, char *args) |
328 | { | 328 | { |
329 | unsigned long frun; | 329 | unsigned long frun; |
330 | 330 | ||
331 | _enter(",%s", args); | 331 | _enter(",%s", args); |
332 | 332 | ||
333 | if (!*args) | 333 | if (!*args) |
334 | return -EINVAL; | 334 | return -EINVAL; |
335 | 335 | ||
336 | frun = simple_strtoul(args, &args, 10); | 336 | frun = simple_strtoul(args, &args, 10); |
337 | if (args[0] != '%' || args[1] != '\0') | 337 | if (args[0] != '%' || args[1] != '\0') |
338 | return -EINVAL; | 338 | return -EINVAL; |
339 | 339 | ||
340 | if (frun <= cache->fcull_percent || frun >= 100) | 340 | if (frun <= cache->fcull_percent || frun >= 100) |
341 | return cachefiles_daemon_range_error(cache, args); | 341 | return cachefiles_daemon_range_error(cache, args); |
342 | 342 | ||
343 | cache->frun_percent = frun; | 343 | cache->frun_percent = frun; |
344 | return 0; | 344 | return 0; |
345 | } | 345 | } |
346 | 346 | ||
347 | /* | 347 | /* |
348 | * set the percentage of files at which to start culling | 348 | * set the percentage of files at which to start culling |
349 | * - command: "fcull <N>%" | 349 | * - command: "fcull <N>%" |
350 | */ | 350 | */ |
351 | static int cachefiles_daemon_fcull(struct cachefiles_cache *cache, char *args) | 351 | static int cachefiles_daemon_fcull(struct cachefiles_cache *cache, char *args) |
352 | { | 352 | { |
353 | unsigned long fcull; | 353 | unsigned long fcull; |
354 | 354 | ||
355 | _enter(",%s", args); | 355 | _enter(",%s", args); |
356 | 356 | ||
357 | if (!*args) | 357 | if (!*args) |
358 | return -EINVAL; | 358 | return -EINVAL; |
359 | 359 | ||
360 | fcull = simple_strtoul(args, &args, 10); | 360 | fcull = simple_strtoul(args, &args, 10); |
361 | if (args[0] != '%' || args[1] != '\0') | 361 | if (args[0] != '%' || args[1] != '\0') |
362 | return -EINVAL; | 362 | return -EINVAL; |
363 | 363 | ||
364 | if (fcull <= cache->fstop_percent || fcull >= cache->frun_percent) | 364 | if (fcull <= cache->fstop_percent || fcull >= cache->frun_percent) |
365 | return cachefiles_daemon_range_error(cache, args); | 365 | return cachefiles_daemon_range_error(cache, args); |
366 | 366 | ||
367 | cache->fcull_percent = fcull; | 367 | cache->fcull_percent = fcull; |
368 | return 0; | 368 | return 0; |
369 | } | 369 | } |
370 | 370 | ||
371 | /* | 371 | /* |
372 | * set the percentage of files at which to stop allocating | 372 | * set the percentage of files at which to stop allocating |
373 | * - command: "fstop <N>%" | 373 | * - command: "fstop <N>%" |
374 | */ | 374 | */ |
375 | static int cachefiles_daemon_fstop(struct cachefiles_cache *cache, char *args) | 375 | static int cachefiles_daemon_fstop(struct cachefiles_cache *cache, char *args) |
376 | { | 376 | { |
377 | unsigned long fstop; | 377 | unsigned long fstop; |
378 | 378 | ||
379 | _enter(",%s", args); | 379 | _enter(",%s", args); |
380 | 380 | ||
381 | if (!*args) | 381 | if (!*args) |
382 | return -EINVAL; | 382 | return -EINVAL; |
383 | 383 | ||
384 | fstop = simple_strtoul(args, &args, 10); | 384 | fstop = simple_strtoul(args, &args, 10); |
385 | if (args[0] != '%' || args[1] != '\0') | 385 | if (args[0] != '%' || args[1] != '\0') |
386 | return -EINVAL; | 386 | return -EINVAL; |
387 | 387 | ||
388 | if (fstop < 0 || fstop >= cache->fcull_percent) | 388 | if (fstop < 0 || fstop >= cache->fcull_percent) |
389 | return cachefiles_daemon_range_error(cache, args); | 389 | return cachefiles_daemon_range_error(cache, args); |
390 | 390 | ||
391 | cache->fstop_percent = fstop; | 391 | cache->fstop_percent = fstop; |
392 | return 0; | 392 | return 0; |
393 | } | 393 | } |
394 | 394 | ||
395 | /* | 395 | /* |
396 | * set the percentage of blocks at which to stop culling | 396 | * set the percentage of blocks at which to stop culling |
397 | * - command: "brun <N>%" | 397 | * - command: "brun <N>%" |
398 | */ | 398 | */ |
399 | static int cachefiles_daemon_brun(struct cachefiles_cache *cache, char *args) | 399 | static int cachefiles_daemon_brun(struct cachefiles_cache *cache, char *args) |
400 | { | 400 | { |
401 | unsigned long brun; | 401 | unsigned long brun; |
402 | 402 | ||
403 | _enter(",%s", args); | 403 | _enter(",%s", args); |
404 | 404 | ||
405 | if (!*args) | 405 | if (!*args) |
406 | return -EINVAL; | 406 | return -EINVAL; |
407 | 407 | ||
408 | brun = simple_strtoul(args, &args, 10); | 408 | brun = simple_strtoul(args, &args, 10); |
409 | if (args[0] != '%' || args[1] != '\0') | 409 | if (args[0] != '%' || args[1] != '\0') |
410 | return -EINVAL; | 410 | return -EINVAL; |
411 | 411 | ||
412 | if (brun <= cache->bcull_percent || brun >= 100) | 412 | if (brun <= cache->bcull_percent || brun >= 100) |
413 | return cachefiles_daemon_range_error(cache, args); | 413 | return cachefiles_daemon_range_error(cache, args); |
414 | 414 | ||
415 | cache->brun_percent = brun; | 415 | cache->brun_percent = brun; |
416 | return 0; | 416 | return 0; |
417 | } | 417 | } |
418 | 418 | ||
419 | /* | 419 | /* |
420 | * set the percentage of blocks at which to start culling | 420 | * set the percentage of blocks at which to start culling |
421 | * - command: "bcull <N>%" | 421 | * - command: "bcull <N>%" |
422 | */ | 422 | */ |
423 | static int cachefiles_daemon_bcull(struct cachefiles_cache *cache, char *args) | 423 | static int cachefiles_daemon_bcull(struct cachefiles_cache *cache, char *args) |
424 | { | 424 | { |
425 | unsigned long bcull; | 425 | unsigned long bcull; |
426 | 426 | ||
427 | _enter(",%s", args); | 427 | _enter(",%s", args); |
428 | 428 | ||
429 | if (!*args) | 429 | if (!*args) |
430 | return -EINVAL; | 430 | return -EINVAL; |
431 | 431 | ||
432 | bcull = simple_strtoul(args, &args, 10); | 432 | bcull = simple_strtoul(args, &args, 10); |
433 | if (args[0] != '%' || args[1] != '\0') | 433 | if (args[0] != '%' || args[1] != '\0') |
434 | return -EINVAL; | 434 | return -EINVAL; |
435 | 435 | ||
436 | if (bcull <= cache->bstop_percent || bcull >= cache->brun_percent) | 436 | if (bcull <= cache->bstop_percent || bcull >= cache->brun_percent) |
437 | return cachefiles_daemon_range_error(cache, args); | 437 | return cachefiles_daemon_range_error(cache, args); |
438 | 438 | ||
439 | cache->bcull_percent = bcull; | 439 | cache->bcull_percent = bcull; |
440 | return 0; | 440 | return 0; |
441 | } | 441 | } |
442 | 442 | ||
443 | /* | 443 | /* |
444 | * set the percentage of blocks at which to stop allocating | 444 | * set the percentage of blocks at which to stop allocating |
445 | * - command: "bstop <N>%" | 445 | * - command: "bstop <N>%" |
446 | */ | 446 | */ |
447 | static int cachefiles_daemon_bstop(struct cachefiles_cache *cache, char *args) | 447 | static int cachefiles_daemon_bstop(struct cachefiles_cache *cache, char *args) |
448 | { | 448 | { |
449 | unsigned long bstop; | 449 | unsigned long bstop; |
450 | 450 | ||
451 | _enter(",%s", args); | 451 | _enter(",%s", args); |
452 | 452 | ||
453 | if (!*args) | 453 | if (!*args) |
454 | return -EINVAL; | 454 | return -EINVAL; |
455 | 455 | ||
456 | bstop = simple_strtoul(args, &args, 10); | 456 | bstop = simple_strtoul(args, &args, 10); |
457 | if (args[0] != '%' || args[1] != '\0') | 457 | if (args[0] != '%' || args[1] != '\0') |
458 | return -EINVAL; | 458 | return -EINVAL; |
459 | 459 | ||
460 | if (bstop < 0 || bstop >= cache->bcull_percent) | 460 | if (bstop < 0 || bstop >= cache->bcull_percent) |
461 | return cachefiles_daemon_range_error(cache, args); | 461 | return cachefiles_daemon_range_error(cache, args); |
462 | 462 | ||
463 | cache->bstop_percent = bstop; | 463 | cache->bstop_percent = bstop; |
464 | return 0; | 464 | return 0; |
465 | } | 465 | } |
466 | 466 | ||
467 | /* | 467 | /* |
468 | * set the cache directory | 468 | * set the cache directory |
469 | * - command: "dir <name>" | 469 | * - command: "dir <name>" |
470 | */ | 470 | */ |
471 | static int cachefiles_daemon_dir(struct cachefiles_cache *cache, char *args) | 471 | static int cachefiles_daemon_dir(struct cachefiles_cache *cache, char *args) |
472 | { | 472 | { |
473 | char *dir; | 473 | char *dir; |
474 | 474 | ||
475 | _enter(",%s", args); | 475 | _enter(",%s", args); |
476 | 476 | ||
477 | if (!*args) { | 477 | if (!*args) { |
478 | kerror("Empty directory specified"); | 478 | kerror("Empty directory specified"); |
479 | return -EINVAL; | 479 | return -EINVAL; |
480 | } | 480 | } |
481 | 481 | ||
482 | if (cache->rootdirname) { | 482 | if (cache->rootdirname) { |
483 | kerror("Second cache directory specified"); | 483 | kerror("Second cache directory specified"); |
484 | return -EEXIST; | 484 | return -EEXIST; |
485 | } | 485 | } |
486 | 486 | ||
487 | dir = kstrdup(args, GFP_KERNEL); | 487 | dir = kstrdup(args, GFP_KERNEL); |
488 | if (!dir) | 488 | if (!dir) |
489 | return -ENOMEM; | 489 | return -ENOMEM; |
490 | 490 | ||
491 | cache->rootdirname = dir; | 491 | cache->rootdirname = dir; |
492 | return 0; | 492 | return 0; |
493 | } | 493 | } |
494 | 494 | ||
495 | /* | 495 | /* |
496 | * set the cache security context | 496 | * set the cache security context |
497 | * - command: "secctx <ctx>" | 497 | * - command: "secctx <ctx>" |
498 | */ | 498 | */ |
499 | static int cachefiles_daemon_secctx(struct cachefiles_cache *cache, char *args) | 499 | static int cachefiles_daemon_secctx(struct cachefiles_cache *cache, char *args) |
500 | { | 500 | { |
501 | char *secctx; | 501 | char *secctx; |
502 | 502 | ||
503 | _enter(",%s", args); | 503 | _enter(",%s", args); |
504 | 504 | ||
505 | if (!*args) { | 505 | if (!*args) { |
506 | kerror("Empty security context specified"); | 506 | kerror("Empty security context specified"); |
507 | return -EINVAL; | 507 | return -EINVAL; |
508 | } | 508 | } |
509 | 509 | ||
510 | if (cache->secctx) { | 510 | if (cache->secctx) { |
511 | kerror("Second security context specified"); | 511 | kerror("Second security context specified"); |
512 | return -EINVAL; | 512 | return -EINVAL; |
513 | } | 513 | } |
514 | 514 | ||
515 | secctx = kstrdup(args, GFP_KERNEL); | 515 | secctx = kstrdup(args, GFP_KERNEL); |
516 | if (!secctx) | 516 | if (!secctx) |
517 | return -ENOMEM; | 517 | return -ENOMEM; |
518 | 518 | ||
519 | cache->secctx = secctx; | 519 | cache->secctx = secctx; |
520 | return 0; | 520 | return 0; |
521 | } | 521 | } |
522 | 522 | ||
523 | /* | 523 | /* |
524 | * set the cache tag | 524 | * set the cache tag |
525 | * - command: "tag <name>" | 525 | * - command: "tag <name>" |
526 | */ | 526 | */ |
527 | static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args) | 527 | static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args) |
528 | { | 528 | { |
529 | char *tag; | 529 | char *tag; |
530 | 530 | ||
531 | _enter(",%s", args); | 531 | _enter(",%s", args); |
532 | 532 | ||
533 | if (!*args) { | 533 | if (!*args) { |
534 | kerror("Empty tag specified"); | 534 | kerror("Empty tag specified"); |
535 | return -EINVAL; | 535 | return -EINVAL; |
536 | } | 536 | } |
537 | 537 | ||
538 | if (cache->tag) | 538 | if (cache->tag) |
539 | return -EEXIST; | 539 | return -EEXIST; |
540 | 540 | ||
541 | tag = kstrdup(args, GFP_KERNEL); | 541 | tag = kstrdup(args, GFP_KERNEL); |
542 | if (!tag) | 542 | if (!tag) |
543 | return -ENOMEM; | 543 | return -ENOMEM; |
544 | 544 | ||
545 | cache->tag = tag; | 545 | cache->tag = tag; |
546 | return 0; | 546 | return 0; |
547 | } | 547 | } |
548 | 548 | ||
549 | /* | 549 | /* |
550 | * request a node in the cache be culled from the current working directory | 550 | * request a node in the cache be culled from the current working directory |
551 | * - command: "cull <name>" | 551 | * - command: "cull <name>" |
552 | */ | 552 | */ |
553 | static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) | 553 | static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) |
554 | { | 554 | { |
555 | struct fs_struct *fs; | 555 | struct fs_struct *fs; |
556 | struct dentry *dir; | 556 | struct path path; |
557 | const struct cred *saved_cred; | 557 | const struct cred *saved_cred; |
558 | int ret; | 558 | int ret; |
559 | 559 | ||
560 | _enter(",%s", args); | 560 | _enter(",%s", args); |
561 | 561 | ||
562 | if (strchr(args, '/')) | 562 | if (strchr(args, '/')) |
563 | goto inval; | 563 | goto inval; |
564 | 564 | ||
565 | if (!test_bit(CACHEFILES_READY, &cache->flags)) { | 565 | if (!test_bit(CACHEFILES_READY, &cache->flags)) { |
566 | kerror("cull applied to unready cache"); | 566 | kerror("cull applied to unready cache"); |
567 | return -EIO; | 567 | return -EIO; |
568 | } | 568 | } |
569 | 569 | ||
570 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) { | 570 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) { |
571 | kerror("cull applied to dead cache"); | 571 | kerror("cull applied to dead cache"); |
572 | return -EIO; | 572 | return -EIO; |
573 | } | 573 | } |
574 | 574 | ||
575 | /* extract the directory dentry from the cwd */ | 575 | /* extract the directory dentry from the cwd */ |
576 | fs = current->fs; | 576 | fs = current->fs; |
577 | read_lock(&fs->lock); | 577 | read_lock(&fs->lock); |
578 | dir = dget(fs->pwd.dentry); | 578 | path = fs->pwd; |
579 | path_get(&path); | ||
579 | read_unlock(&fs->lock); | 580 | read_unlock(&fs->lock); |
580 | 581 | ||
581 | if (!S_ISDIR(dir->d_inode->i_mode)) | 582 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) |
582 | goto notdir; | 583 | goto notdir; |
583 | 584 | ||
584 | cachefiles_begin_secure(cache, &saved_cred); | 585 | cachefiles_begin_secure(cache, &saved_cred); |
585 | ret = cachefiles_cull(cache, dir, args); | 586 | ret = cachefiles_cull(cache, path.dentry, args); |
586 | cachefiles_end_secure(cache, saved_cred); | 587 | cachefiles_end_secure(cache, saved_cred); |
587 | 588 | ||
588 | dput(dir); | 589 | path_put(&path); |
589 | _leave(" = %d", ret); | 590 | _leave(" = %d", ret); |
590 | return ret; | 591 | return ret; |
591 | 592 | ||
592 | notdir: | 593 | notdir: |
593 | dput(dir); | 594 | path_put(&path); |
594 | kerror("cull command requires dirfd to be a directory"); | 595 | kerror("cull command requires dirfd to be a directory"); |
595 | return -ENOTDIR; | 596 | return -ENOTDIR; |
596 | 597 | ||
597 | inval: | 598 | inval: |
598 | kerror("cull command requires dirfd and filename"); | 599 | kerror("cull command requires dirfd and filename"); |
599 | return -EINVAL; | 600 | return -EINVAL; |
600 | } | 601 | } |
601 | 602 | ||
602 | /* | 603 | /* |
603 | * set debugging mode | 604 | * set debugging mode |
604 | * - command: "debug <mask>" | 605 | * - command: "debug <mask>" |
605 | */ | 606 | */ |
606 | static int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args) | 607 | static int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args) |
607 | { | 608 | { |
608 | unsigned long mask; | 609 | unsigned long mask; |
609 | 610 | ||
610 | _enter(",%s", args); | 611 | _enter(",%s", args); |
611 | 612 | ||
612 | mask = simple_strtoul(args, &args, 0); | 613 | mask = simple_strtoul(args, &args, 0); |
613 | if (args[0] != '\0') | 614 | if (args[0] != '\0') |
614 | goto inval; | 615 | goto inval; |
615 | 616 | ||
616 | cachefiles_debug = mask; | 617 | cachefiles_debug = mask; |
617 | _leave(" = 0"); | 618 | _leave(" = 0"); |
618 | return 0; | 619 | return 0; |
619 | 620 | ||
620 | inval: | 621 | inval: |
621 | kerror("debug command requires mask"); | 622 | kerror("debug command requires mask"); |
622 | return -EINVAL; | 623 | return -EINVAL; |
623 | } | 624 | } |
624 | 625 | ||
625 | /* | 626 | /* |
626 | * find out whether an object in the current working directory is in use or not | 627 | * find out whether an object in the current working directory is in use or not |
627 | * - command: "inuse <name>" | 628 | * - command: "inuse <name>" |
628 | */ | 629 | */ |
629 | static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) | 630 | static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) |
630 | { | 631 | { |
631 | struct fs_struct *fs; | 632 | struct fs_struct *fs; |
632 | struct dentry *dir; | 633 | struct path path; |
633 | const struct cred *saved_cred; | 634 | const struct cred *saved_cred; |
634 | int ret; | 635 | int ret; |
635 | 636 | ||
636 | //_enter(",%s", args); | 637 | //_enter(",%s", args); |
637 | 638 | ||
638 | if (strchr(args, '/')) | 639 | if (strchr(args, '/')) |
639 | goto inval; | 640 | goto inval; |
640 | 641 | ||
641 | if (!test_bit(CACHEFILES_READY, &cache->flags)) { | 642 | if (!test_bit(CACHEFILES_READY, &cache->flags)) { |
642 | kerror("inuse applied to unready cache"); | 643 | kerror("inuse applied to unready cache"); |
643 | return -EIO; | 644 | return -EIO; |
644 | } | 645 | } |
645 | 646 | ||
646 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) { | 647 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) { |
647 | kerror("inuse applied to dead cache"); | 648 | kerror("inuse applied to dead cache"); |
648 | return -EIO; | 649 | return -EIO; |
649 | } | 650 | } |
650 | 651 | ||
651 | /* extract the directory dentry from the cwd */ | 652 | /* extract the directory dentry from the cwd */ |
652 | fs = current->fs; | 653 | fs = current->fs; |
653 | read_lock(&fs->lock); | 654 | read_lock(&fs->lock); |
654 | dir = dget(fs->pwd.dentry); | 655 | path = fs->pwd; |
656 | path_get(&path); | ||
655 | read_unlock(&fs->lock); | 657 | read_unlock(&fs->lock); |
656 | 658 | ||
657 | if (!S_ISDIR(dir->d_inode->i_mode)) | 659 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) |
658 | goto notdir; | 660 | goto notdir; |
659 | 661 | ||
660 | cachefiles_begin_secure(cache, &saved_cred); | 662 | cachefiles_begin_secure(cache, &saved_cred); |
661 | ret = cachefiles_check_in_use(cache, dir, args); | 663 | ret = cachefiles_check_in_use(cache, path.dentry, args); |
662 | cachefiles_end_secure(cache, saved_cred); | 664 | cachefiles_end_secure(cache, saved_cred); |
663 | 665 | ||
664 | dput(dir); | 666 | path_put(&path); |
665 | //_leave(" = %d", ret); | 667 | //_leave(" = %d", ret); |
666 | return ret; | 668 | return ret; |
667 | 669 | ||
668 | notdir: | 670 | notdir: |
669 | dput(dir); | 671 | path_put(&path); |
670 | kerror("inuse command requires dirfd to be a directory"); | 672 | kerror("inuse command requires dirfd to be a directory"); |
671 | return -ENOTDIR; | 673 | return -ENOTDIR; |
672 | 674 | ||
673 | inval: | 675 | inval: |
674 | kerror("inuse command requires dirfd and filename"); | 676 | kerror("inuse command requires dirfd and filename"); |
675 | return -EINVAL; | 677 | return -EINVAL; |
676 | } | 678 | } |
677 | 679 | ||
678 | /* | 680 | /* |
679 | * see if we have space for a number of pages and/or a number of files in the | 681 | * see if we have space for a number of pages and/or a number of files in the |
680 | * cache | 682 | * cache |
681 | */ | 683 | */ |
682 | int cachefiles_has_space(struct cachefiles_cache *cache, | 684 | int cachefiles_has_space(struct cachefiles_cache *cache, |
683 | unsigned fnr, unsigned bnr) | 685 | unsigned fnr, unsigned bnr) |
684 | { | 686 | { |
685 | struct kstatfs stats; | 687 | struct kstatfs stats; |
686 | struct path path = { | 688 | struct path path = { |
687 | .mnt = cache->mnt, | 689 | .mnt = cache->mnt, |
688 | .dentry = cache->mnt->mnt_root, | 690 | .dentry = cache->mnt->mnt_root, |
689 | }; | 691 | }; |
690 | int ret; | 692 | int ret; |
691 | 693 | ||
692 | //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u", | 694 | //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u", |
693 | // (unsigned long long) cache->frun, | 695 | // (unsigned long long) cache->frun, |
694 | // (unsigned long long) cache->fcull, | 696 | // (unsigned long long) cache->fcull, |
695 | // (unsigned long long) cache->fstop, | 697 | // (unsigned long long) cache->fstop, |
696 | // (unsigned long long) cache->brun, | 698 | // (unsigned long long) cache->brun, |
697 | // (unsigned long long) cache->bcull, | 699 | // (unsigned long long) cache->bcull, |
698 | // (unsigned long long) cache->bstop, | 700 | // (unsigned long long) cache->bstop, |
699 | // fnr, bnr); | 701 | // fnr, bnr); |
700 | 702 | ||
701 | /* find out how many pages of blockdev are available */ | 703 | /* find out how many pages of blockdev are available */ |
702 | memset(&stats, 0, sizeof(stats)); | 704 | memset(&stats, 0, sizeof(stats)); |
703 | 705 | ||
704 | ret = vfs_statfs(&path, &stats); | 706 | ret = vfs_statfs(&path, &stats); |
705 | if (ret < 0) { | 707 | if (ret < 0) { |
706 | if (ret == -EIO) | 708 | if (ret == -EIO) |
707 | cachefiles_io_error(cache, "statfs failed"); | 709 | cachefiles_io_error(cache, "statfs failed"); |
708 | _leave(" = %d", ret); | 710 | _leave(" = %d", ret); |
709 | return ret; | 711 | return ret; |
710 | } | 712 | } |
711 | 713 | ||
712 | stats.f_bavail >>= cache->bshift; | 714 | stats.f_bavail >>= cache->bshift; |
713 | 715 | ||
714 | //_debug("avail %llu,%llu", | 716 | //_debug("avail %llu,%llu", |
715 | // (unsigned long long) stats.f_ffree, | 717 | // (unsigned long long) stats.f_ffree, |
716 | // (unsigned long long) stats.f_bavail); | 718 | // (unsigned long long) stats.f_bavail); |
717 | 719 | ||
718 | /* see if there is sufficient space */ | 720 | /* see if there is sufficient space */ |
719 | if (stats.f_ffree > fnr) | 721 | if (stats.f_ffree > fnr) |
720 | stats.f_ffree -= fnr; | 722 | stats.f_ffree -= fnr; |
721 | else | 723 | else |
722 | stats.f_ffree = 0; | 724 | stats.f_ffree = 0; |
723 | 725 | ||
724 | if (stats.f_bavail > bnr) | 726 | if (stats.f_bavail > bnr) |
725 | stats.f_bavail -= bnr; | 727 | stats.f_bavail -= bnr; |
726 | else | 728 | else |
727 | stats.f_bavail = 0; | 729 | stats.f_bavail = 0; |
728 | 730 | ||
729 | ret = -ENOBUFS; | 731 | ret = -ENOBUFS; |
730 | if (stats.f_ffree < cache->fstop || | 732 | if (stats.f_ffree < cache->fstop || |
731 | stats.f_bavail < cache->bstop) | 733 | stats.f_bavail < cache->bstop) |
732 | goto begin_cull; | 734 | goto begin_cull; |
733 | 735 | ||
734 | ret = 0; | 736 | ret = 0; |
735 | if (stats.f_ffree < cache->fcull || | 737 | if (stats.f_ffree < cache->fcull || |
736 | stats.f_bavail < cache->bcull) | 738 | stats.f_bavail < cache->bcull) |
737 | goto begin_cull; | 739 | goto begin_cull; |
738 | 740 | ||
739 | if (test_bit(CACHEFILES_CULLING, &cache->flags) && | 741 | if (test_bit(CACHEFILES_CULLING, &cache->flags) && |
740 | stats.f_ffree >= cache->frun && | 742 | stats.f_ffree >= cache->frun && |
741 | stats.f_bavail >= cache->brun && | 743 | stats.f_bavail >= cache->brun && |
742 | test_and_clear_bit(CACHEFILES_CULLING, &cache->flags) | 744 | test_and_clear_bit(CACHEFILES_CULLING, &cache->flags) |
743 | ) { | 745 | ) { |
744 | _debug("cease culling"); | 746 | _debug("cease culling"); |
745 | cachefiles_state_changed(cache); | 747 | cachefiles_state_changed(cache); |
746 | } | 748 | } |
747 | 749 | ||
748 | //_leave(" = 0"); | 750 | //_leave(" = 0"); |
749 | return 0; | 751 | return 0; |
750 | 752 | ||
751 | begin_cull: | 753 | begin_cull: |
752 | if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) { | 754 | if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) { |
753 | _debug("### CULL CACHE ###"); | 755 | _debug("### CULL CACHE ###"); |
754 | cachefiles_state_changed(cache); | 756 | cachefiles_state_changed(cache); |
755 | } | 757 | } |
756 | 758 | ||
757 | _leave(" = %d", ret); | 759 | _leave(" = %d", ret); |
758 | return ret; | 760 | return ret; |
759 | } | 761 | } |
760 | 762 |