Commit 6ff66ac77aeaa9c13db28784e1c50c027a1f487b
Committed by
Linus Torvalds
1 parent
6f3aabd183
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
fs/cachefiles: add missing \n to kerror conversions
Commit 0227d6abb378 ("fs/cachefiles: replace kerror by pr_err") didn't include newline featuring in original kerror definition Signed-off-by: Fabian Frederick <fabf@skynet.be> Reported-by: David Howells <dhowells@redhat.com> Acked-by: David Howells <dhowells@redhat.com> Cc: <stable@vger.kernel.org> [3.16.x] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 6 changed files with 33 additions and 33 deletions Inline Diff
fs/cachefiles/bind.c
1 | /* Bind and unbind a cache from the filesystem backing it | 1 | /* Bind and unbind a cache from the filesystem backing it |
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/mount.h> | 20 | #include <linux/mount.h> |
21 | #include <linux/statfs.h> | 21 | #include <linux/statfs.h> |
22 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
23 | #include "internal.h" | 23 | #include "internal.h" |
24 | 24 | ||
25 | static int cachefiles_daemon_add_cache(struct cachefiles_cache *caches); | 25 | static int cachefiles_daemon_add_cache(struct cachefiles_cache *caches); |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * bind a directory as a cache | 28 | * bind a directory as a cache |
29 | */ | 29 | */ |
30 | int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args) | 30 | int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args) |
31 | { | 31 | { |
32 | _enter("{%u,%u,%u,%u,%u,%u},%s", | 32 | _enter("{%u,%u,%u,%u,%u,%u},%s", |
33 | cache->frun_percent, | 33 | cache->frun_percent, |
34 | cache->fcull_percent, | 34 | cache->fcull_percent, |
35 | cache->fstop_percent, | 35 | cache->fstop_percent, |
36 | cache->brun_percent, | 36 | cache->brun_percent, |
37 | cache->bcull_percent, | 37 | cache->bcull_percent, |
38 | cache->bstop_percent, | 38 | cache->bstop_percent, |
39 | args); | 39 | args); |
40 | 40 | ||
41 | /* start by checking things over */ | 41 | /* start by checking things over */ |
42 | ASSERT(cache->fstop_percent >= 0 && | 42 | ASSERT(cache->fstop_percent >= 0 && |
43 | cache->fstop_percent < cache->fcull_percent && | 43 | cache->fstop_percent < cache->fcull_percent && |
44 | cache->fcull_percent < cache->frun_percent && | 44 | cache->fcull_percent < cache->frun_percent && |
45 | cache->frun_percent < 100); | 45 | cache->frun_percent < 100); |
46 | 46 | ||
47 | ASSERT(cache->bstop_percent >= 0 && | 47 | ASSERT(cache->bstop_percent >= 0 && |
48 | cache->bstop_percent < cache->bcull_percent && | 48 | cache->bstop_percent < cache->bcull_percent && |
49 | cache->bcull_percent < cache->brun_percent && | 49 | cache->bcull_percent < cache->brun_percent && |
50 | cache->brun_percent < 100); | 50 | cache->brun_percent < 100); |
51 | 51 | ||
52 | if (*args) { | 52 | if (*args) { |
53 | pr_err("'bind' command doesn't take an argument"); | 53 | pr_err("'bind' command doesn't take an argument\n"); |
54 | return -EINVAL; | 54 | return -EINVAL; |
55 | } | 55 | } |
56 | 56 | ||
57 | if (!cache->rootdirname) { | 57 | if (!cache->rootdirname) { |
58 | pr_err("No cache directory specified"); | 58 | pr_err("No cache directory specified\n"); |
59 | return -EINVAL; | 59 | return -EINVAL; |
60 | } | 60 | } |
61 | 61 | ||
62 | /* don't permit already bound caches to be re-bound */ | 62 | /* don't permit already bound caches to be re-bound */ |
63 | if (test_bit(CACHEFILES_READY, &cache->flags)) { | 63 | if (test_bit(CACHEFILES_READY, &cache->flags)) { |
64 | pr_err("Cache already bound"); | 64 | pr_err("Cache already bound\n"); |
65 | return -EBUSY; | 65 | return -EBUSY; |
66 | } | 66 | } |
67 | 67 | ||
68 | /* make sure we have copies of the tag and dirname strings */ | 68 | /* make sure we have copies of the tag and dirname strings */ |
69 | if (!cache->tag) { | 69 | if (!cache->tag) { |
70 | /* the tag string is released by the fops->release() | 70 | /* the tag string is released by the fops->release() |
71 | * function, so we don't release it on error here */ | 71 | * function, so we don't release it on error here */ |
72 | cache->tag = kstrdup("CacheFiles", GFP_KERNEL); | 72 | cache->tag = kstrdup("CacheFiles", GFP_KERNEL); |
73 | if (!cache->tag) | 73 | if (!cache->tag) |
74 | return -ENOMEM; | 74 | return -ENOMEM; |
75 | } | 75 | } |
76 | 76 | ||
77 | /* add the cache */ | 77 | /* add the cache */ |
78 | return cachefiles_daemon_add_cache(cache); | 78 | return cachefiles_daemon_add_cache(cache); |
79 | } | 79 | } |
80 | 80 | ||
81 | /* | 81 | /* |
82 | * add a cache | 82 | * add a cache |
83 | */ | 83 | */ |
84 | static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) | 84 | static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) |
85 | { | 85 | { |
86 | struct cachefiles_object *fsdef; | 86 | struct cachefiles_object *fsdef; |
87 | struct path path; | 87 | struct path path; |
88 | struct kstatfs stats; | 88 | struct kstatfs stats; |
89 | struct dentry *graveyard, *cachedir, *root; | 89 | struct dentry *graveyard, *cachedir, *root; |
90 | const struct cred *saved_cred; | 90 | const struct cred *saved_cred; |
91 | int ret; | 91 | int ret; |
92 | 92 | ||
93 | _enter(""); | 93 | _enter(""); |
94 | 94 | ||
95 | /* we want to work under the module's security ID */ | 95 | /* we want to work under the module's security ID */ |
96 | ret = cachefiles_get_security_ID(cache); | 96 | ret = cachefiles_get_security_ID(cache); |
97 | if (ret < 0) | 97 | if (ret < 0) |
98 | return ret; | 98 | return ret; |
99 | 99 | ||
100 | cachefiles_begin_secure(cache, &saved_cred); | 100 | cachefiles_begin_secure(cache, &saved_cred); |
101 | 101 | ||
102 | /* allocate the root index object */ | 102 | /* allocate the root index object */ |
103 | ret = -ENOMEM; | 103 | ret = -ENOMEM; |
104 | 104 | ||
105 | fsdef = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL); | 105 | fsdef = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL); |
106 | if (!fsdef) | 106 | if (!fsdef) |
107 | goto error_root_object; | 107 | goto error_root_object; |
108 | 108 | ||
109 | ASSERTCMP(fsdef->backer, ==, NULL); | 109 | ASSERTCMP(fsdef->backer, ==, NULL); |
110 | 110 | ||
111 | atomic_set(&fsdef->usage, 1); | 111 | atomic_set(&fsdef->usage, 1); |
112 | fsdef->type = FSCACHE_COOKIE_TYPE_INDEX; | 112 | fsdef->type = FSCACHE_COOKIE_TYPE_INDEX; |
113 | 113 | ||
114 | _debug("- fsdef %p", fsdef); | 114 | _debug("- fsdef %p", fsdef); |
115 | 115 | ||
116 | /* look up the directory at the root of the cache */ | 116 | /* look up the directory at the root of the cache */ |
117 | ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path); | 117 | ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path); |
118 | if (ret < 0) | 118 | if (ret < 0) |
119 | goto error_open_root; | 119 | goto error_open_root; |
120 | 120 | ||
121 | cache->mnt = path.mnt; | 121 | cache->mnt = path.mnt; |
122 | root = path.dentry; | 122 | root = path.dentry; |
123 | 123 | ||
124 | /* check parameters */ | 124 | /* check parameters */ |
125 | ret = -EOPNOTSUPP; | 125 | ret = -EOPNOTSUPP; |
126 | if (!root->d_inode || | 126 | if (!root->d_inode || |
127 | !root->d_inode->i_op->lookup || | 127 | !root->d_inode->i_op->lookup || |
128 | !root->d_inode->i_op->mkdir || | 128 | !root->d_inode->i_op->mkdir || |
129 | !root->d_inode->i_op->setxattr || | 129 | !root->d_inode->i_op->setxattr || |
130 | !root->d_inode->i_op->getxattr || | 130 | !root->d_inode->i_op->getxattr || |
131 | !root->d_sb->s_op->statfs || | 131 | !root->d_sb->s_op->statfs || |
132 | !root->d_sb->s_op->sync_fs) | 132 | !root->d_sb->s_op->sync_fs) |
133 | goto error_unsupported; | 133 | goto error_unsupported; |
134 | 134 | ||
135 | ret = -EROFS; | 135 | ret = -EROFS; |
136 | if (root->d_sb->s_flags & MS_RDONLY) | 136 | if (root->d_sb->s_flags & MS_RDONLY) |
137 | goto error_unsupported; | 137 | goto error_unsupported; |
138 | 138 | ||
139 | /* determine the security of the on-disk cache as this governs | 139 | /* determine the security of the on-disk cache as this governs |
140 | * security ID of files we create */ | 140 | * security ID of files we create */ |
141 | ret = cachefiles_determine_cache_security(cache, root, &saved_cred); | 141 | ret = cachefiles_determine_cache_security(cache, root, &saved_cred); |
142 | if (ret < 0) | 142 | if (ret < 0) |
143 | goto error_unsupported; | 143 | goto error_unsupported; |
144 | 144 | ||
145 | /* get the cache size and blocksize */ | 145 | /* get the cache size and blocksize */ |
146 | ret = vfs_statfs(&path, &stats); | 146 | ret = vfs_statfs(&path, &stats); |
147 | if (ret < 0) | 147 | if (ret < 0) |
148 | goto error_unsupported; | 148 | goto error_unsupported; |
149 | 149 | ||
150 | ret = -ERANGE; | 150 | ret = -ERANGE; |
151 | if (stats.f_bsize <= 0) | 151 | if (stats.f_bsize <= 0) |
152 | goto error_unsupported; | 152 | goto error_unsupported; |
153 | 153 | ||
154 | ret = -EOPNOTSUPP; | 154 | ret = -EOPNOTSUPP; |
155 | if (stats.f_bsize > PAGE_SIZE) | 155 | if (stats.f_bsize > PAGE_SIZE) |
156 | goto error_unsupported; | 156 | goto error_unsupported; |
157 | 157 | ||
158 | cache->bsize = stats.f_bsize; | 158 | cache->bsize = stats.f_bsize; |
159 | cache->bshift = 0; | 159 | cache->bshift = 0; |
160 | if (stats.f_bsize < PAGE_SIZE) | 160 | if (stats.f_bsize < PAGE_SIZE) |
161 | cache->bshift = PAGE_SHIFT - ilog2(stats.f_bsize); | 161 | cache->bshift = PAGE_SHIFT - ilog2(stats.f_bsize); |
162 | 162 | ||
163 | _debug("blksize %u (shift %u)", | 163 | _debug("blksize %u (shift %u)", |
164 | cache->bsize, cache->bshift); | 164 | cache->bsize, cache->bshift); |
165 | 165 | ||
166 | _debug("size %llu, avail %llu", | 166 | _debug("size %llu, avail %llu", |
167 | (unsigned long long) stats.f_blocks, | 167 | (unsigned long long) stats.f_blocks, |
168 | (unsigned long long) stats.f_bavail); | 168 | (unsigned long long) stats.f_bavail); |
169 | 169 | ||
170 | /* set up caching limits */ | 170 | /* set up caching limits */ |
171 | do_div(stats.f_files, 100); | 171 | do_div(stats.f_files, 100); |
172 | cache->fstop = stats.f_files * cache->fstop_percent; | 172 | cache->fstop = stats.f_files * cache->fstop_percent; |
173 | cache->fcull = stats.f_files * cache->fcull_percent; | 173 | cache->fcull = stats.f_files * cache->fcull_percent; |
174 | cache->frun = stats.f_files * cache->frun_percent; | 174 | cache->frun = stats.f_files * cache->frun_percent; |
175 | 175 | ||
176 | _debug("limits {%llu,%llu,%llu} files", | 176 | _debug("limits {%llu,%llu,%llu} files", |
177 | (unsigned long long) cache->frun, | 177 | (unsigned long long) cache->frun, |
178 | (unsigned long long) cache->fcull, | 178 | (unsigned long long) cache->fcull, |
179 | (unsigned long long) cache->fstop); | 179 | (unsigned long long) cache->fstop); |
180 | 180 | ||
181 | stats.f_blocks >>= cache->bshift; | 181 | stats.f_blocks >>= cache->bshift; |
182 | do_div(stats.f_blocks, 100); | 182 | do_div(stats.f_blocks, 100); |
183 | cache->bstop = stats.f_blocks * cache->bstop_percent; | 183 | cache->bstop = stats.f_blocks * cache->bstop_percent; |
184 | cache->bcull = stats.f_blocks * cache->bcull_percent; | 184 | cache->bcull = stats.f_blocks * cache->bcull_percent; |
185 | cache->brun = stats.f_blocks * cache->brun_percent; | 185 | cache->brun = stats.f_blocks * cache->brun_percent; |
186 | 186 | ||
187 | _debug("limits {%llu,%llu,%llu} blocks", | 187 | _debug("limits {%llu,%llu,%llu} blocks", |
188 | (unsigned long long) cache->brun, | 188 | (unsigned long long) cache->brun, |
189 | (unsigned long long) cache->bcull, | 189 | (unsigned long long) cache->bcull, |
190 | (unsigned long long) cache->bstop); | 190 | (unsigned long long) cache->bstop); |
191 | 191 | ||
192 | /* get the cache directory and check its type */ | 192 | /* get the cache directory and check its type */ |
193 | cachedir = cachefiles_get_directory(cache, root, "cache"); | 193 | cachedir = cachefiles_get_directory(cache, root, "cache"); |
194 | if (IS_ERR(cachedir)) { | 194 | if (IS_ERR(cachedir)) { |
195 | ret = PTR_ERR(cachedir); | 195 | ret = PTR_ERR(cachedir); |
196 | goto error_unsupported; | 196 | goto error_unsupported; |
197 | } | 197 | } |
198 | 198 | ||
199 | fsdef->dentry = cachedir; | 199 | fsdef->dentry = cachedir; |
200 | fsdef->fscache.cookie = NULL; | 200 | fsdef->fscache.cookie = NULL; |
201 | 201 | ||
202 | ret = cachefiles_check_object_type(fsdef); | 202 | ret = cachefiles_check_object_type(fsdef); |
203 | if (ret < 0) | 203 | if (ret < 0) |
204 | goto error_unsupported; | 204 | goto error_unsupported; |
205 | 205 | ||
206 | /* get the graveyard directory */ | 206 | /* get the graveyard directory */ |
207 | graveyard = cachefiles_get_directory(cache, root, "graveyard"); | 207 | graveyard = cachefiles_get_directory(cache, root, "graveyard"); |
208 | if (IS_ERR(graveyard)) { | 208 | if (IS_ERR(graveyard)) { |
209 | ret = PTR_ERR(graveyard); | 209 | ret = PTR_ERR(graveyard); |
210 | goto error_unsupported; | 210 | goto error_unsupported; |
211 | } | 211 | } |
212 | 212 | ||
213 | cache->graveyard = graveyard; | 213 | cache->graveyard = graveyard; |
214 | 214 | ||
215 | /* publish the cache */ | 215 | /* publish the cache */ |
216 | fscache_init_cache(&cache->cache, | 216 | fscache_init_cache(&cache->cache, |
217 | &cachefiles_cache_ops, | 217 | &cachefiles_cache_ops, |
218 | "%s", | 218 | "%s", |
219 | fsdef->dentry->d_sb->s_id); | 219 | fsdef->dentry->d_sb->s_id); |
220 | 220 | ||
221 | fscache_object_init(&fsdef->fscache, NULL, &cache->cache); | 221 | fscache_object_init(&fsdef->fscache, NULL, &cache->cache); |
222 | 222 | ||
223 | ret = fscache_add_cache(&cache->cache, &fsdef->fscache, cache->tag); | 223 | ret = fscache_add_cache(&cache->cache, &fsdef->fscache, cache->tag); |
224 | if (ret < 0) | 224 | if (ret < 0) |
225 | goto error_add_cache; | 225 | goto error_add_cache; |
226 | 226 | ||
227 | /* done */ | 227 | /* done */ |
228 | set_bit(CACHEFILES_READY, &cache->flags); | 228 | set_bit(CACHEFILES_READY, &cache->flags); |
229 | dput(root); | 229 | dput(root); |
230 | 230 | ||
231 | pr_info("File cache on %s registered\n", cache->cache.identifier); | 231 | pr_info("File cache on %s registered\n", cache->cache.identifier); |
232 | 232 | ||
233 | /* check how much space the cache has */ | 233 | /* check how much space the cache has */ |
234 | cachefiles_has_space(cache, 0, 0); | 234 | cachefiles_has_space(cache, 0, 0); |
235 | cachefiles_end_secure(cache, saved_cred); | 235 | cachefiles_end_secure(cache, saved_cred); |
236 | return 0; | 236 | return 0; |
237 | 237 | ||
238 | error_add_cache: | 238 | error_add_cache: |
239 | dput(cache->graveyard); | 239 | dput(cache->graveyard); |
240 | cache->graveyard = NULL; | 240 | cache->graveyard = NULL; |
241 | error_unsupported: | 241 | error_unsupported: |
242 | mntput(cache->mnt); | 242 | mntput(cache->mnt); |
243 | cache->mnt = NULL; | 243 | cache->mnt = NULL; |
244 | dput(fsdef->dentry); | 244 | dput(fsdef->dentry); |
245 | fsdef->dentry = NULL; | 245 | fsdef->dentry = NULL; |
246 | dput(root); | 246 | dput(root); |
247 | error_open_root: | 247 | error_open_root: |
248 | kmem_cache_free(cachefiles_object_jar, fsdef); | 248 | kmem_cache_free(cachefiles_object_jar, fsdef); |
249 | error_root_object: | 249 | error_root_object: |
250 | cachefiles_end_secure(cache, saved_cred); | 250 | cachefiles_end_secure(cache, saved_cred); |
251 | pr_err("Failed to register: %d", ret); | 251 | pr_err("Failed to register: %d\n", ret); |
252 | return ret; | 252 | return ret; |
253 | } | 253 | } |
254 | 254 | ||
255 | /* | 255 | /* |
256 | * unbind a cache on fd release | 256 | * unbind a cache on fd release |
257 | */ | 257 | */ |
258 | void cachefiles_daemon_unbind(struct cachefiles_cache *cache) | 258 | void cachefiles_daemon_unbind(struct cachefiles_cache *cache) |
259 | { | 259 | { |
260 | _enter(""); | 260 | _enter(""); |
261 | 261 | ||
262 | if (test_bit(CACHEFILES_READY, &cache->flags)) { | 262 | if (test_bit(CACHEFILES_READY, &cache->flags)) { |
263 | pr_info("File cache on %s unregistering\n", | 263 | pr_info("File cache on %s unregistering\n", |
264 | cache->cache.identifier); | 264 | cache->cache.identifier); |
265 | 265 | ||
266 | fscache_withdraw_cache(&cache->cache); | 266 | fscache_withdraw_cache(&cache->cache); |
267 | } | 267 | } |
268 | 268 | ||
269 | dput(cache->graveyard); | 269 | dput(cache->graveyard); |
270 | mntput(cache->mnt); | 270 | mntput(cache->mnt); |
271 | 271 | ||
272 | kfree(cache->rootdirname); | 272 | kfree(cache->rootdirname); |
273 | kfree(cache->secctx); | 273 | kfree(cache->secctx); |
274 | kfree(cache->tag); | 274 | kfree(cache->tag); |
275 | 275 | ||
276 | _leave(""); | 276 | _leave(""); |
277 | } | 277 | } |
278 | 278 |
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 | .llseek = noop_llseek, | 58 | .llseek = noop_llseek, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | struct cachefiles_daemon_cmd { | 61 | struct cachefiles_daemon_cmd { |
62 | char name[8]; | 62 | char name[8]; |
63 | int (*handler)(struct cachefiles_cache *cache, char *args); | 63 | int (*handler)(struct cachefiles_cache *cache, char *args); |
64 | }; | 64 | }; |
65 | 65 | ||
66 | static const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = { | 66 | static const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = { |
67 | { "bind", cachefiles_daemon_bind }, | 67 | { "bind", cachefiles_daemon_bind }, |
68 | { "brun", cachefiles_daemon_brun }, | 68 | { "brun", cachefiles_daemon_brun }, |
69 | { "bcull", cachefiles_daemon_bcull }, | 69 | { "bcull", cachefiles_daemon_bcull }, |
70 | { "bstop", cachefiles_daemon_bstop }, | 70 | { "bstop", cachefiles_daemon_bstop }, |
71 | { "cull", cachefiles_daemon_cull }, | 71 | { "cull", cachefiles_daemon_cull }, |
72 | { "debug", cachefiles_daemon_debug }, | 72 | { "debug", cachefiles_daemon_debug }, |
73 | { "dir", cachefiles_daemon_dir }, | 73 | { "dir", cachefiles_daemon_dir }, |
74 | { "frun", cachefiles_daemon_frun }, | 74 | { "frun", cachefiles_daemon_frun }, |
75 | { "fcull", cachefiles_daemon_fcull }, | 75 | { "fcull", cachefiles_daemon_fcull }, |
76 | { "fstop", cachefiles_daemon_fstop }, | 76 | { "fstop", cachefiles_daemon_fstop }, |
77 | { "inuse", cachefiles_daemon_inuse }, | 77 | { "inuse", cachefiles_daemon_inuse }, |
78 | { "secctx", cachefiles_daemon_secctx }, | 78 | { "secctx", cachefiles_daemon_secctx }, |
79 | { "tag", cachefiles_daemon_tag }, | 79 | { "tag", cachefiles_daemon_tag }, |
80 | { "", NULL } | 80 | { "", NULL } |
81 | }; | 81 | }; |
82 | 82 | ||
83 | 83 | ||
84 | /* | 84 | /* |
85 | * do various checks | 85 | * do various checks |
86 | */ | 86 | */ |
87 | static int cachefiles_daemon_open(struct inode *inode, struct file *file) | 87 | static int cachefiles_daemon_open(struct inode *inode, struct file *file) |
88 | { | 88 | { |
89 | struct cachefiles_cache *cache; | 89 | struct cachefiles_cache *cache; |
90 | 90 | ||
91 | _enter(""); | 91 | _enter(""); |
92 | 92 | ||
93 | /* only the superuser may do this */ | 93 | /* only the superuser may do this */ |
94 | if (!capable(CAP_SYS_ADMIN)) | 94 | if (!capable(CAP_SYS_ADMIN)) |
95 | return -EPERM; | 95 | return -EPERM; |
96 | 96 | ||
97 | /* the cachefiles device may only be open once at a time */ | 97 | /* the cachefiles device may only be open once at a time */ |
98 | if (xchg(&cachefiles_open, 1) == 1) | 98 | if (xchg(&cachefiles_open, 1) == 1) |
99 | return -EBUSY; | 99 | return -EBUSY; |
100 | 100 | ||
101 | /* allocate a cache record */ | 101 | /* allocate a cache record */ |
102 | cache = kzalloc(sizeof(struct cachefiles_cache), GFP_KERNEL); | 102 | cache = kzalloc(sizeof(struct cachefiles_cache), GFP_KERNEL); |
103 | if (!cache) { | 103 | if (!cache) { |
104 | cachefiles_open = 0; | 104 | cachefiles_open = 0; |
105 | return -ENOMEM; | 105 | return -ENOMEM; |
106 | } | 106 | } |
107 | 107 | ||
108 | mutex_init(&cache->daemon_mutex); | 108 | mutex_init(&cache->daemon_mutex); |
109 | cache->active_nodes = RB_ROOT; | 109 | cache->active_nodes = RB_ROOT; |
110 | rwlock_init(&cache->active_lock); | 110 | rwlock_init(&cache->active_lock); |
111 | init_waitqueue_head(&cache->daemon_pollwq); | 111 | init_waitqueue_head(&cache->daemon_pollwq); |
112 | 112 | ||
113 | /* set default caching limits | 113 | /* set default caching limits |
114 | * - limit at 1% free space and/or free files | 114 | * - limit at 1% free space and/or free files |
115 | * - cull below 5% free space and/or free files | 115 | * - cull below 5% free space and/or free files |
116 | * - cease culling above 7% free space and/or free files | 116 | * - cease culling above 7% free space and/or free files |
117 | */ | 117 | */ |
118 | cache->frun_percent = 7; | 118 | cache->frun_percent = 7; |
119 | cache->fcull_percent = 5; | 119 | cache->fcull_percent = 5; |
120 | cache->fstop_percent = 1; | 120 | cache->fstop_percent = 1; |
121 | cache->brun_percent = 7; | 121 | cache->brun_percent = 7; |
122 | cache->bcull_percent = 5; | 122 | cache->bcull_percent = 5; |
123 | cache->bstop_percent = 1; | 123 | cache->bstop_percent = 1; |
124 | 124 | ||
125 | file->private_data = cache; | 125 | file->private_data = cache; |
126 | cache->cachefilesd = file; | 126 | cache->cachefilesd = file; |
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * release a cache | 131 | * release a cache |
132 | */ | 132 | */ |
133 | static int cachefiles_daemon_release(struct inode *inode, struct file *file) | 133 | static int cachefiles_daemon_release(struct inode *inode, struct file *file) |
134 | { | 134 | { |
135 | struct cachefiles_cache *cache = file->private_data; | 135 | struct cachefiles_cache *cache = file->private_data; |
136 | 136 | ||
137 | _enter(""); | 137 | _enter(""); |
138 | 138 | ||
139 | ASSERT(cache); | 139 | ASSERT(cache); |
140 | 140 | ||
141 | set_bit(CACHEFILES_DEAD, &cache->flags); | 141 | set_bit(CACHEFILES_DEAD, &cache->flags); |
142 | 142 | ||
143 | cachefiles_daemon_unbind(cache); | 143 | cachefiles_daemon_unbind(cache); |
144 | 144 | ||
145 | ASSERT(!cache->active_nodes.rb_node); | 145 | ASSERT(!cache->active_nodes.rb_node); |
146 | 146 | ||
147 | /* clean up the control file interface */ | 147 | /* clean up the control file interface */ |
148 | cache->cachefilesd = NULL; | 148 | cache->cachefilesd = NULL; |
149 | file->private_data = NULL; | 149 | file->private_data = NULL; |
150 | cachefiles_open = 0; | 150 | cachefiles_open = 0; |
151 | 151 | ||
152 | kfree(cache); | 152 | kfree(cache); |
153 | 153 | ||
154 | _leave(""); | 154 | _leave(""); |
155 | return 0; | 155 | return 0; |
156 | } | 156 | } |
157 | 157 | ||
158 | /* | 158 | /* |
159 | * read the cache state | 159 | * read the cache state |
160 | */ | 160 | */ |
161 | static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer, | 161 | static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer, |
162 | size_t buflen, loff_t *pos) | 162 | size_t buflen, loff_t *pos) |
163 | { | 163 | { |
164 | struct cachefiles_cache *cache = file->private_data; | 164 | struct cachefiles_cache *cache = file->private_data; |
165 | char buffer[256]; | 165 | char buffer[256]; |
166 | int n; | 166 | int n; |
167 | 167 | ||
168 | //_enter(",,%zu,", buflen); | 168 | //_enter(",,%zu,", buflen); |
169 | 169 | ||
170 | if (!test_bit(CACHEFILES_READY, &cache->flags)) | 170 | if (!test_bit(CACHEFILES_READY, &cache->flags)) |
171 | return 0; | 171 | return 0; |
172 | 172 | ||
173 | /* check how much space the cache has */ | 173 | /* check how much space the cache has */ |
174 | cachefiles_has_space(cache, 0, 0); | 174 | cachefiles_has_space(cache, 0, 0); |
175 | 175 | ||
176 | /* summarise */ | 176 | /* summarise */ |
177 | clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags); | 177 | clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags); |
178 | 178 | ||
179 | n = snprintf(buffer, sizeof(buffer), | 179 | n = snprintf(buffer, sizeof(buffer), |
180 | "cull=%c" | 180 | "cull=%c" |
181 | " frun=%llx" | 181 | " frun=%llx" |
182 | " fcull=%llx" | 182 | " fcull=%llx" |
183 | " fstop=%llx" | 183 | " fstop=%llx" |
184 | " brun=%llx" | 184 | " brun=%llx" |
185 | " bcull=%llx" | 185 | " bcull=%llx" |
186 | " bstop=%llx", | 186 | " bstop=%llx", |
187 | test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0', | 187 | test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0', |
188 | (unsigned long long) cache->frun, | 188 | (unsigned long long) cache->frun, |
189 | (unsigned long long) cache->fcull, | 189 | (unsigned long long) cache->fcull, |
190 | (unsigned long long) cache->fstop, | 190 | (unsigned long long) cache->fstop, |
191 | (unsigned long long) cache->brun, | 191 | (unsigned long long) cache->brun, |
192 | (unsigned long long) cache->bcull, | 192 | (unsigned long long) cache->bcull, |
193 | (unsigned long long) cache->bstop | 193 | (unsigned long long) cache->bstop |
194 | ); | 194 | ); |
195 | 195 | ||
196 | if (n > buflen) | 196 | if (n > buflen) |
197 | return -EMSGSIZE; | 197 | return -EMSGSIZE; |
198 | 198 | ||
199 | if (copy_to_user(_buffer, buffer, n) != 0) | 199 | if (copy_to_user(_buffer, buffer, n) != 0) |
200 | return -EFAULT; | 200 | return -EFAULT; |
201 | 201 | ||
202 | return n; | 202 | return n; |
203 | } | 203 | } |
204 | 204 | ||
205 | /* | 205 | /* |
206 | * command the cache | 206 | * command the cache |
207 | */ | 207 | */ |
208 | static ssize_t cachefiles_daemon_write(struct file *file, | 208 | static ssize_t cachefiles_daemon_write(struct file *file, |
209 | const char __user *_data, | 209 | const char __user *_data, |
210 | size_t datalen, | 210 | size_t datalen, |
211 | loff_t *pos) | 211 | loff_t *pos) |
212 | { | 212 | { |
213 | const struct cachefiles_daemon_cmd *cmd; | 213 | const struct cachefiles_daemon_cmd *cmd; |
214 | struct cachefiles_cache *cache = file->private_data; | 214 | struct cachefiles_cache *cache = file->private_data; |
215 | ssize_t ret; | 215 | ssize_t ret; |
216 | char *data, *args, *cp; | 216 | char *data, *args, *cp; |
217 | 217 | ||
218 | //_enter(",,%zu,", datalen); | 218 | //_enter(",,%zu,", datalen); |
219 | 219 | ||
220 | ASSERT(cache); | 220 | ASSERT(cache); |
221 | 221 | ||
222 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) | 222 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) |
223 | return -EIO; | 223 | return -EIO; |
224 | 224 | ||
225 | if (datalen < 0 || datalen > PAGE_SIZE - 1) | 225 | if (datalen < 0 || datalen > PAGE_SIZE - 1) |
226 | return -EOPNOTSUPP; | 226 | return -EOPNOTSUPP; |
227 | 227 | ||
228 | /* drag the command string into the kernel so we can parse it */ | 228 | /* drag the command string into the kernel so we can parse it */ |
229 | data = kmalloc(datalen + 1, GFP_KERNEL); | 229 | data = kmalloc(datalen + 1, GFP_KERNEL); |
230 | if (!data) | 230 | if (!data) |
231 | return -ENOMEM; | 231 | return -ENOMEM; |
232 | 232 | ||
233 | ret = -EFAULT; | 233 | ret = -EFAULT; |
234 | if (copy_from_user(data, _data, datalen) != 0) | 234 | if (copy_from_user(data, _data, datalen) != 0) |
235 | goto error; | 235 | goto error; |
236 | 236 | ||
237 | data[datalen] = '\0'; | 237 | data[datalen] = '\0'; |
238 | 238 | ||
239 | ret = -EINVAL; | 239 | ret = -EINVAL; |
240 | if (memchr(data, '\0', datalen)) | 240 | if (memchr(data, '\0', datalen)) |
241 | goto error; | 241 | goto error; |
242 | 242 | ||
243 | /* strip any newline */ | 243 | /* strip any newline */ |
244 | cp = memchr(data, '\n', datalen); | 244 | cp = memchr(data, '\n', datalen); |
245 | if (cp) { | 245 | if (cp) { |
246 | if (cp == data) | 246 | if (cp == data) |
247 | goto error; | 247 | goto error; |
248 | 248 | ||
249 | *cp = '\0'; | 249 | *cp = '\0'; |
250 | } | 250 | } |
251 | 251 | ||
252 | /* parse the command */ | 252 | /* parse the command */ |
253 | ret = -EOPNOTSUPP; | 253 | ret = -EOPNOTSUPP; |
254 | 254 | ||
255 | for (args = data; *args; args++) | 255 | for (args = data; *args; args++) |
256 | if (isspace(*args)) | 256 | if (isspace(*args)) |
257 | break; | 257 | break; |
258 | if (*args) { | 258 | if (*args) { |
259 | if (args == data) | 259 | if (args == data) |
260 | goto error; | 260 | goto error; |
261 | *args = '\0'; | 261 | *args = '\0'; |
262 | args = skip_spaces(++args); | 262 | args = skip_spaces(++args); |
263 | } | 263 | } |
264 | 264 | ||
265 | /* run the appropriate command handler */ | 265 | /* run the appropriate command handler */ |
266 | for (cmd = cachefiles_daemon_cmds; cmd->name[0]; cmd++) | 266 | for (cmd = cachefiles_daemon_cmds; cmd->name[0]; cmd++) |
267 | if (strcmp(cmd->name, data) == 0) | 267 | if (strcmp(cmd->name, data) == 0) |
268 | goto found_command; | 268 | goto found_command; |
269 | 269 | ||
270 | error: | 270 | error: |
271 | kfree(data); | 271 | kfree(data); |
272 | //_leave(" = %zd", ret); | 272 | //_leave(" = %zd", ret); |
273 | return ret; | 273 | return ret; |
274 | 274 | ||
275 | found_command: | 275 | found_command: |
276 | mutex_lock(&cache->daemon_mutex); | 276 | mutex_lock(&cache->daemon_mutex); |
277 | 277 | ||
278 | ret = -EIO; | 278 | ret = -EIO; |
279 | if (!test_bit(CACHEFILES_DEAD, &cache->flags)) | 279 | if (!test_bit(CACHEFILES_DEAD, &cache->flags)) |
280 | ret = cmd->handler(cache, args); | 280 | ret = cmd->handler(cache, args); |
281 | 281 | ||
282 | mutex_unlock(&cache->daemon_mutex); | 282 | mutex_unlock(&cache->daemon_mutex); |
283 | 283 | ||
284 | if (ret == 0) | 284 | if (ret == 0) |
285 | ret = datalen; | 285 | ret = datalen; |
286 | goto error; | 286 | goto error; |
287 | } | 287 | } |
288 | 288 | ||
289 | /* | 289 | /* |
290 | * poll for culling state | 290 | * poll for culling state |
291 | * - use POLLOUT to indicate culling state | 291 | * - use POLLOUT to indicate culling state |
292 | */ | 292 | */ |
293 | static unsigned int cachefiles_daemon_poll(struct file *file, | 293 | static unsigned int cachefiles_daemon_poll(struct file *file, |
294 | struct poll_table_struct *poll) | 294 | struct poll_table_struct *poll) |
295 | { | 295 | { |
296 | struct cachefiles_cache *cache = file->private_data; | 296 | struct cachefiles_cache *cache = file->private_data; |
297 | unsigned int mask; | 297 | unsigned int mask; |
298 | 298 | ||
299 | poll_wait(file, &cache->daemon_pollwq, poll); | 299 | poll_wait(file, &cache->daemon_pollwq, poll); |
300 | mask = 0; | 300 | mask = 0; |
301 | 301 | ||
302 | if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags)) | 302 | if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags)) |
303 | mask |= POLLIN; | 303 | mask |= POLLIN; |
304 | 304 | ||
305 | if (test_bit(CACHEFILES_CULLING, &cache->flags)) | 305 | if (test_bit(CACHEFILES_CULLING, &cache->flags)) |
306 | mask |= POLLOUT; | 306 | mask |= POLLOUT; |
307 | 307 | ||
308 | return mask; | 308 | return mask; |
309 | } | 309 | } |
310 | 310 | ||
311 | /* | 311 | /* |
312 | * give a range error for cache space constraints | 312 | * give a range error for cache space constraints |
313 | * - can be tail-called | 313 | * - can be tail-called |
314 | */ | 314 | */ |
315 | static int cachefiles_daemon_range_error(struct cachefiles_cache *cache, | 315 | static int cachefiles_daemon_range_error(struct cachefiles_cache *cache, |
316 | char *args) | 316 | char *args) |
317 | { | 317 | { |
318 | pr_err("Free space limits must be in range 0%%<=stop<cull<run<100%%"); | 318 | pr_err("Free space limits must be in range 0%%<=stop<cull<run<100%%\n"); |
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 | pr_err("Empty directory specified"); | 478 | pr_err("Empty directory specified\n"); |
479 | return -EINVAL; | 479 | return -EINVAL; |
480 | } | 480 | } |
481 | 481 | ||
482 | if (cache->rootdirname) { | 482 | if (cache->rootdirname) { |
483 | pr_err("Second cache directory specified"); | 483 | pr_err("Second cache directory specified\n"); |
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 | pr_err("Empty security context specified"); | 506 | pr_err("Empty security context specified\n"); |
507 | return -EINVAL; | 507 | return -EINVAL; |
508 | } | 508 | } |
509 | 509 | ||
510 | if (cache->secctx) { | 510 | if (cache->secctx) { |
511 | pr_err("Second security context specified"); | 511 | pr_err("Second security context specified\n"); |
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 | pr_err("Empty tag specified"); | 534 | pr_err("Empty tag specified\n"); |
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 path path; | 555 | struct path path; |
556 | const struct cred *saved_cred; | 556 | const struct cred *saved_cred; |
557 | int ret; | 557 | int ret; |
558 | 558 | ||
559 | _enter(",%s", args); | 559 | _enter(",%s", args); |
560 | 560 | ||
561 | if (strchr(args, '/')) | 561 | if (strchr(args, '/')) |
562 | goto inval; | 562 | goto inval; |
563 | 563 | ||
564 | if (!test_bit(CACHEFILES_READY, &cache->flags)) { | 564 | if (!test_bit(CACHEFILES_READY, &cache->flags)) { |
565 | pr_err("cull applied to unready cache"); | 565 | pr_err("cull applied to unready cache\n"); |
566 | return -EIO; | 566 | return -EIO; |
567 | } | 567 | } |
568 | 568 | ||
569 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) { | 569 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) { |
570 | pr_err("cull applied to dead cache"); | 570 | pr_err("cull applied to dead cache\n"); |
571 | return -EIO; | 571 | return -EIO; |
572 | } | 572 | } |
573 | 573 | ||
574 | /* extract the directory dentry from the cwd */ | 574 | /* extract the directory dentry from the cwd */ |
575 | get_fs_pwd(current->fs, &path); | 575 | get_fs_pwd(current->fs, &path); |
576 | 576 | ||
577 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) | 577 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) |
578 | goto notdir; | 578 | goto notdir; |
579 | 579 | ||
580 | cachefiles_begin_secure(cache, &saved_cred); | 580 | cachefiles_begin_secure(cache, &saved_cred); |
581 | ret = cachefiles_cull(cache, path.dentry, args); | 581 | ret = cachefiles_cull(cache, path.dentry, args); |
582 | cachefiles_end_secure(cache, saved_cred); | 582 | cachefiles_end_secure(cache, saved_cred); |
583 | 583 | ||
584 | path_put(&path); | 584 | path_put(&path); |
585 | _leave(" = %d", ret); | 585 | _leave(" = %d", ret); |
586 | return ret; | 586 | return ret; |
587 | 587 | ||
588 | notdir: | 588 | notdir: |
589 | path_put(&path); | 589 | path_put(&path); |
590 | pr_err("cull command requires dirfd to be a directory"); | 590 | pr_err("cull command requires dirfd to be a directory\n"); |
591 | return -ENOTDIR; | 591 | return -ENOTDIR; |
592 | 592 | ||
593 | inval: | 593 | inval: |
594 | pr_err("cull command requires dirfd and filename"); | 594 | pr_err("cull command requires dirfd and filename\n"); |
595 | return -EINVAL; | 595 | return -EINVAL; |
596 | } | 596 | } |
597 | 597 | ||
598 | /* | 598 | /* |
599 | * set debugging mode | 599 | * set debugging mode |
600 | * - command: "debug <mask>" | 600 | * - command: "debug <mask>" |
601 | */ | 601 | */ |
602 | static int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args) | 602 | static int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args) |
603 | { | 603 | { |
604 | unsigned long mask; | 604 | unsigned long mask; |
605 | 605 | ||
606 | _enter(",%s", args); | 606 | _enter(",%s", args); |
607 | 607 | ||
608 | mask = simple_strtoul(args, &args, 0); | 608 | mask = simple_strtoul(args, &args, 0); |
609 | if (args[0] != '\0') | 609 | if (args[0] != '\0') |
610 | goto inval; | 610 | goto inval; |
611 | 611 | ||
612 | cachefiles_debug = mask; | 612 | cachefiles_debug = mask; |
613 | _leave(" = 0"); | 613 | _leave(" = 0"); |
614 | return 0; | 614 | return 0; |
615 | 615 | ||
616 | inval: | 616 | inval: |
617 | pr_err("debug command requires mask"); | 617 | pr_err("debug command requires mask\n"); |
618 | return -EINVAL; | 618 | return -EINVAL; |
619 | } | 619 | } |
620 | 620 | ||
621 | /* | 621 | /* |
622 | * find out whether an object in the current working directory is in use or not | 622 | * find out whether an object in the current working directory is in use or not |
623 | * - command: "inuse <name>" | 623 | * - command: "inuse <name>" |
624 | */ | 624 | */ |
625 | static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) | 625 | static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) |
626 | { | 626 | { |
627 | struct path path; | 627 | struct path path; |
628 | const struct cred *saved_cred; | 628 | const struct cred *saved_cred; |
629 | int ret; | 629 | int ret; |
630 | 630 | ||
631 | //_enter(",%s", args); | 631 | //_enter(",%s", args); |
632 | 632 | ||
633 | if (strchr(args, '/')) | 633 | if (strchr(args, '/')) |
634 | goto inval; | 634 | goto inval; |
635 | 635 | ||
636 | if (!test_bit(CACHEFILES_READY, &cache->flags)) { | 636 | if (!test_bit(CACHEFILES_READY, &cache->flags)) { |
637 | pr_err("inuse applied to unready cache"); | 637 | pr_err("inuse applied to unready cache\n"); |
638 | return -EIO; | 638 | return -EIO; |
639 | } | 639 | } |
640 | 640 | ||
641 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) { | 641 | if (test_bit(CACHEFILES_DEAD, &cache->flags)) { |
642 | pr_err("inuse applied to dead cache"); | 642 | pr_err("inuse applied to dead cache\n"); |
643 | return -EIO; | 643 | return -EIO; |
644 | } | 644 | } |
645 | 645 | ||
646 | /* extract the directory dentry from the cwd */ | 646 | /* extract the directory dentry from the cwd */ |
647 | get_fs_pwd(current->fs, &path); | 647 | get_fs_pwd(current->fs, &path); |
648 | 648 | ||
649 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) | 649 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) |
650 | goto notdir; | 650 | goto notdir; |
651 | 651 | ||
652 | cachefiles_begin_secure(cache, &saved_cred); | 652 | cachefiles_begin_secure(cache, &saved_cred); |
653 | ret = cachefiles_check_in_use(cache, path.dentry, args); | 653 | ret = cachefiles_check_in_use(cache, path.dentry, args); |
654 | cachefiles_end_secure(cache, saved_cred); | 654 | cachefiles_end_secure(cache, saved_cred); |
655 | 655 | ||
656 | path_put(&path); | 656 | path_put(&path); |
657 | //_leave(" = %d", ret); | 657 | //_leave(" = %d", ret); |
658 | return ret; | 658 | return ret; |
659 | 659 | ||
660 | notdir: | 660 | notdir: |
661 | path_put(&path); | 661 | path_put(&path); |
662 | pr_err("inuse command requires dirfd to be a directory"); | 662 | pr_err("inuse command requires dirfd to be a directory\n"); |
663 | return -ENOTDIR; | 663 | return -ENOTDIR; |
664 | 664 | ||
665 | inval: | 665 | inval: |
666 | pr_err("inuse command requires dirfd and filename"); | 666 | pr_err("inuse command requires dirfd and filename\n"); |
667 | return -EINVAL; | 667 | return -EINVAL; |
668 | } | 668 | } |
669 | 669 | ||
670 | /* | 670 | /* |
671 | * see if we have space for a number of pages and/or a number of files in the | 671 | * see if we have space for a number of pages and/or a number of files in the |
672 | * cache | 672 | * cache |
673 | */ | 673 | */ |
674 | int cachefiles_has_space(struct cachefiles_cache *cache, | 674 | int cachefiles_has_space(struct cachefiles_cache *cache, |
675 | unsigned fnr, unsigned bnr) | 675 | unsigned fnr, unsigned bnr) |
676 | { | 676 | { |
677 | struct kstatfs stats; | 677 | struct kstatfs stats; |
678 | struct path path = { | 678 | struct path path = { |
679 | .mnt = cache->mnt, | 679 | .mnt = cache->mnt, |
680 | .dentry = cache->mnt->mnt_root, | 680 | .dentry = cache->mnt->mnt_root, |
681 | }; | 681 | }; |
682 | int ret; | 682 | int ret; |
683 | 683 | ||
684 | //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u", | 684 | //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u", |
685 | // (unsigned long long) cache->frun, | 685 | // (unsigned long long) cache->frun, |
686 | // (unsigned long long) cache->fcull, | 686 | // (unsigned long long) cache->fcull, |
687 | // (unsigned long long) cache->fstop, | 687 | // (unsigned long long) cache->fstop, |
688 | // (unsigned long long) cache->brun, | 688 | // (unsigned long long) cache->brun, |
689 | // (unsigned long long) cache->bcull, | 689 | // (unsigned long long) cache->bcull, |
690 | // (unsigned long long) cache->bstop, | 690 | // (unsigned long long) cache->bstop, |
691 | // fnr, bnr); | 691 | // fnr, bnr); |
692 | 692 | ||
693 | /* find out how many pages of blockdev are available */ | 693 | /* find out how many pages of blockdev are available */ |
694 | memset(&stats, 0, sizeof(stats)); | 694 | memset(&stats, 0, sizeof(stats)); |
695 | 695 | ||
696 | ret = vfs_statfs(&path, &stats); | 696 | ret = vfs_statfs(&path, &stats); |
697 | if (ret < 0) { | 697 | if (ret < 0) { |
698 | if (ret == -EIO) | 698 | if (ret == -EIO) |
699 | cachefiles_io_error(cache, "statfs failed"); | 699 | cachefiles_io_error(cache, "statfs failed"); |
700 | _leave(" = %d", ret); | 700 | _leave(" = %d", ret); |
701 | return ret; | 701 | return ret; |
702 | } | 702 | } |
703 | 703 | ||
704 | stats.f_bavail >>= cache->bshift; | 704 | stats.f_bavail >>= cache->bshift; |
705 | 705 | ||
706 | //_debug("avail %llu,%llu", | 706 | //_debug("avail %llu,%llu", |
707 | // (unsigned long long) stats.f_ffree, | 707 | // (unsigned long long) stats.f_ffree, |
708 | // (unsigned long long) stats.f_bavail); | 708 | // (unsigned long long) stats.f_bavail); |
709 | 709 | ||
710 | /* see if there is sufficient space */ | 710 | /* see if there is sufficient space */ |
711 | if (stats.f_ffree > fnr) | 711 | if (stats.f_ffree > fnr) |
712 | stats.f_ffree -= fnr; | 712 | stats.f_ffree -= fnr; |
713 | else | 713 | else |
714 | stats.f_ffree = 0; | 714 | stats.f_ffree = 0; |
715 | 715 | ||
716 | if (stats.f_bavail > bnr) | 716 | if (stats.f_bavail > bnr) |
717 | stats.f_bavail -= bnr; | 717 | stats.f_bavail -= bnr; |
718 | else | 718 | else |
719 | stats.f_bavail = 0; | 719 | stats.f_bavail = 0; |
720 | 720 | ||
721 | ret = -ENOBUFS; | 721 | ret = -ENOBUFS; |
722 | if (stats.f_ffree < cache->fstop || | 722 | if (stats.f_ffree < cache->fstop || |
723 | stats.f_bavail < cache->bstop) | 723 | stats.f_bavail < cache->bstop) |
724 | goto begin_cull; | 724 | goto begin_cull; |
725 | 725 | ||
726 | ret = 0; | 726 | ret = 0; |
727 | if (stats.f_ffree < cache->fcull || | 727 | if (stats.f_ffree < cache->fcull || |
728 | stats.f_bavail < cache->bcull) | 728 | stats.f_bavail < cache->bcull) |
729 | goto begin_cull; | 729 | goto begin_cull; |
730 | 730 | ||
731 | if (test_bit(CACHEFILES_CULLING, &cache->flags) && | 731 | if (test_bit(CACHEFILES_CULLING, &cache->flags) && |
732 | stats.f_ffree >= cache->frun && | 732 | stats.f_ffree >= cache->frun && |
733 | stats.f_bavail >= cache->brun && | 733 | stats.f_bavail >= cache->brun && |
734 | test_and_clear_bit(CACHEFILES_CULLING, &cache->flags) | 734 | test_and_clear_bit(CACHEFILES_CULLING, &cache->flags) |
735 | ) { | 735 | ) { |
736 | _debug("cease culling"); | 736 | _debug("cease culling"); |
737 | cachefiles_state_changed(cache); | 737 | cachefiles_state_changed(cache); |
738 | } | 738 | } |
739 | 739 | ||
740 | //_leave(" = 0"); | 740 | //_leave(" = 0"); |
741 | return 0; | 741 | return 0; |
742 | 742 | ||
743 | begin_cull: | 743 | begin_cull: |
744 | if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) { | 744 | if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) { |
745 | _debug("### CULL CACHE ###"); | 745 | _debug("### CULL CACHE ###"); |
746 | cachefiles_state_changed(cache); | 746 | cachefiles_state_changed(cache); |
747 | } | 747 | } |
748 | 748 | ||
749 | _leave(" = %d", ret); | 749 | _leave(" = %d", ret); |
750 | return ret; | 750 | return ret; |
751 | } | 751 | } |
752 | 752 |
fs/cachefiles/internal.h
1 | /* General netfs cache on cache files internal defs | 1 | /* General netfs cache on cache files internal defs |
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 | #ifdef pr_fmt | 12 | #ifdef pr_fmt |
13 | #undef pr_fmt | 13 | #undef pr_fmt |
14 | #endif | 14 | #endif |
15 | 15 | ||
16 | #define pr_fmt(fmt) "CacheFiles: " fmt | 16 | #define pr_fmt(fmt) "CacheFiles: " fmt |
17 | 17 | ||
18 | 18 | ||
19 | #include <linux/fscache-cache.h> | 19 | #include <linux/fscache-cache.h> |
20 | #include <linux/timer.h> | 20 | #include <linux/timer.h> |
21 | #include <linux/wait.h> | 21 | #include <linux/wait.h> |
22 | #include <linux/workqueue.h> | 22 | #include <linux/workqueue.h> |
23 | #include <linux/security.h> | 23 | #include <linux/security.h> |
24 | 24 | ||
25 | struct cachefiles_cache; | 25 | struct cachefiles_cache; |
26 | struct cachefiles_object; | 26 | struct cachefiles_object; |
27 | 27 | ||
28 | extern unsigned cachefiles_debug; | 28 | extern unsigned cachefiles_debug; |
29 | #define CACHEFILES_DEBUG_KENTER 1 | 29 | #define CACHEFILES_DEBUG_KENTER 1 |
30 | #define CACHEFILES_DEBUG_KLEAVE 2 | 30 | #define CACHEFILES_DEBUG_KLEAVE 2 |
31 | #define CACHEFILES_DEBUG_KDEBUG 4 | 31 | #define CACHEFILES_DEBUG_KDEBUG 4 |
32 | 32 | ||
33 | #define cachefiles_gfp (__GFP_WAIT | __GFP_NORETRY | __GFP_NOMEMALLOC) | 33 | #define cachefiles_gfp (__GFP_WAIT | __GFP_NORETRY | __GFP_NOMEMALLOC) |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * node records | 36 | * node records |
37 | */ | 37 | */ |
38 | struct cachefiles_object { | 38 | struct cachefiles_object { |
39 | struct fscache_object fscache; /* fscache handle */ | 39 | struct fscache_object fscache; /* fscache handle */ |
40 | struct cachefiles_lookup_data *lookup_data; /* cached lookup data */ | 40 | struct cachefiles_lookup_data *lookup_data; /* cached lookup data */ |
41 | struct dentry *dentry; /* the file/dir representing this object */ | 41 | struct dentry *dentry; /* the file/dir representing this object */ |
42 | struct dentry *backer; /* backing file */ | 42 | struct dentry *backer; /* backing file */ |
43 | loff_t i_size; /* object size */ | 43 | loff_t i_size; /* object size */ |
44 | unsigned long flags; | 44 | unsigned long flags; |
45 | #define CACHEFILES_OBJECT_ACTIVE 0 /* T if marked active */ | 45 | #define CACHEFILES_OBJECT_ACTIVE 0 /* T if marked active */ |
46 | #define CACHEFILES_OBJECT_BURIED 1 /* T if preemptively buried */ | 46 | #define CACHEFILES_OBJECT_BURIED 1 /* T if preemptively buried */ |
47 | atomic_t usage; /* object usage count */ | 47 | atomic_t usage; /* object usage count */ |
48 | uint8_t type; /* object type */ | 48 | uint8_t type; /* object type */ |
49 | uint8_t new; /* T if object new */ | 49 | uint8_t new; /* T if object new */ |
50 | spinlock_t work_lock; | 50 | spinlock_t work_lock; |
51 | struct rb_node active_node; /* link in active tree (dentry is key) */ | 51 | struct rb_node active_node; /* link in active tree (dentry is key) */ |
52 | }; | 52 | }; |
53 | 53 | ||
54 | extern struct kmem_cache *cachefiles_object_jar; | 54 | extern struct kmem_cache *cachefiles_object_jar; |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Cache files cache definition | 57 | * Cache files cache definition |
58 | */ | 58 | */ |
59 | struct cachefiles_cache { | 59 | struct cachefiles_cache { |
60 | struct fscache_cache cache; /* FS-Cache record */ | 60 | struct fscache_cache cache; /* FS-Cache record */ |
61 | struct vfsmount *mnt; /* mountpoint holding the cache */ | 61 | struct vfsmount *mnt; /* mountpoint holding the cache */ |
62 | struct dentry *graveyard; /* directory into which dead objects go */ | 62 | struct dentry *graveyard; /* directory into which dead objects go */ |
63 | struct file *cachefilesd; /* manager daemon handle */ | 63 | struct file *cachefilesd; /* manager daemon handle */ |
64 | const struct cred *cache_cred; /* security override for accessing cache */ | 64 | const struct cred *cache_cred; /* security override for accessing cache */ |
65 | struct mutex daemon_mutex; /* command serialisation mutex */ | 65 | struct mutex daemon_mutex; /* command serialisation mutex */ |
66 | wait_queue_head_t daemon_pollwq; /* poll waitqueue for daemon */ | 66 | wait_queue_head_t daemon_pollwq; /* poll waitqueue for daemon */ |
67 | struct rb_root active_nodes; /* active nodes (can't be culled) */ | 67 | struct rb_root active_nodes; /* active nodes (can't be culled) */ |
68 | rwlock_t active_lock; /* lock for active_nodes */ | 68 | rwlock_t active_lock; /* lock for active_nodes */ |
69 | atomic_t gravecounter; /* graveyard uniquifier */ | 69 | atomic_t gravecounter; /* graveyard uniquifier */ |
70 | unsigned frun_percent; /* when to stop culling (% files) */ | 70 | unsigned frun_percent; /* when to stop culling (% files) */ |
71 | unsigned fcull_percent; /* when to start culling (% files) */ | 71 | unsigned fcull_percent; /* when to start culling (% files) */ |
72 | unsigned fstop_percent; /* when to stop allocating (% files) */ | 72 | unsigned fstop_percent; /* when to stop allocating (% files) */ |
73 | unsigned brun_percent; /* when to stop culling (% blocks) */ | 73 | unsigned brun_percent; /* when to stop culling (% blocks) */ |
74 | unsigned bcull_percent; /* when to start culling (% blocks) */ | 74 | unsigned bcull_percent; /* when to start culling (% blocks) */ |
75 | unsigned bstop_percent; /* when to stop allocating (% blocks) */ | 75 | unsigned bstop_percent; /* when to stop allocating (% blocks) */ |
76 | unsigned bsize; /* cache's block size */ | 76 | unsigned bsize; /* cache's block size */ |
77 | unsigned bshift; /* min(ilog2(PAGE_SIZE / bsize), 0) */ | 77 | unsigned bshift; /* min(ilog2(PAGE_SIZE / bsize), 0) */ |
78 | uint64_t frun; /* when to stop culling */ | 78 | uint64_t frun; /* when to stop culling */ |
79 | uint64_t fcull; /* when to start culling */ | 79 | uint64_t fcull; /* when to start culling */ |
80 | uint64_t fstop; /* when to stop allocating */ | 80 | uint64_t fstop; /* when to stop allocating */ |
81 | sector_t brun; /* when to stop culling */ | 81 | sector_t brun; /* when to stop culling */ |
82 | sector_t bcull; /* when to start culling */ | 82 | sector_t bcull; /* when to start culling */ |
83 | sector_t bstop; /* when to stop allocating */ | 83 | sector_t bstop; /* when to stop allocating */ |
84 | unsigned long flags; | 84 | unsigned long flags; |
85 | #define CACHEFILES_READY 0 /* T if cache prepared */ | 85 | #define CACHEFILES_READY 0 /* T if cache prepared */ |
86 | #define CACHEFILES_DEAD 1 /* T if cache dead */ | 86 | #define CACHEFILES_DEAD 1 /* T if cache dead */ |
87 | #define CACHEFILES_CULLING 2 /* T if cull engaged */ | 87 | #define CACHEFILES_CULLING 2 /* T if cull engaged */ |
88 | #define CACHEFILES_STATE_CHANGED 3 /* T if state changed (poll trigger) */ | 88 | #define CACHEFILES_STATE_CHANGED 3 /* T if state changed (poll trigger) */ |
89 | char *rootdirname; /* name of cache root directory */ | 89 | char *rootdirname; /* name of cache root directory */ |
90 | char *secctx; /* LSM security context */ | 90 | char *secctx; /* LSM security context */ |
91 | char *tag; /* cache binding tag */ | 91 | char *tag; /* cache binding tag */ |
92 | }; | 92 | }; |
93 | 93 | ||
94 | /* | 94 | /* |
95 | * backing file read tracking | 95 | * backing file read tracking |
96 | */ | 96 | */ |
97 | struct cachefiles_one_read { | 97 | struct cachefiles_one_read { |
98 | wait_queue_t monitor; /* link into monitored waitqueue */ | 98 | wait_queue_t monitor; /* link into monitored waitqueue */ |
99 | struct page *back_page; /* backing file page we're waiting for */ | 99 | struct page *back_page; /* backing file page we're waiting for */ |
100 | struct page *netfs_page; /* netfs page we're going to fill */ | 100 | struct page *netfs_page; /* netfs page we're going to fill */ |
101 | struct fscache_retrieval *op; /* retrieval op covering this */ | 101 | struct fscache_retrieval *op; /* retrieval op covering this */ |
102 | struct list_head op_link; /* link in op's todo list */ | 102 | struct list_head op_link; /* link in op's todo list */ |
103 | }; | 103 | }; |
104 | 104 | ||
105 | /* | 105 | /* |
106 | * backing file write tracking | 106 | * backing file write tracking |
107 | */ | 107 | */ |
108 | struct cachefiles_one_write { | 108 | struct cachefiles_one_write { |
109 | struct page *netfs_page; /* netfs page to copy */ | 109 | struct page *netfs_page; /* netfs page to copy */ |
110 | struct cachefiles_object *object; | 110 | struct cachefiles_object *object; |
111 | struct list_head obj_link; /* link in object's lists */ | 111 | struct list_head obj_link; /* link in object's lists */ |
112 | fscache_rw_complete_t end_io_func; | 112 | fscache_rw_complete_t end_io_func; |
113 | void *context; | 113 | void *context; |
114 | }; | 114 | }; |
115 | 115 | ||
116 | /* | 116 | /* |
117 | * auxiliary data xattr buffer | 117 | * auxiliary data xattr buffer |
118 | */ | 118 | */ |
119 | struct cachefiles_xattr { | 119 | struct cachefiles_xattr { |
120 | uint16_t len; | 120 | uint16_t len; |
121 | uint8_t type; | 121 | uint8_t type; |
122 | uint8_t data[]; | 122 | uint8_t data[]; |
123 | }; | 123 | }; |
124 | 124 | ||
125 | /* | 125 | /* |
126 | * note change of state for daemon | 126 | * note change of state for daemon |
127 | */ | 127 | */ |
128 | static inline void cachefiles_state_changed(struct cachefiles_cache *cache) | 128 | static inline void cachefiles_state_changed(struct cachefiles_cache *cache) |
129 | { | 129 | { |
130 | set_bit(CACHEFILES_STATE_CHANGED, &cache->flags); | 130 | set_bit(CACHEFILES_STATE_CHANGED, &cache->flags); |
131 | wake_up_all(&cache->daemon_pollwq); | 131 | wake_up_all(&cache->daemon_pollwq); |
132 | } | 132 | } |
133 | 133 | ||
134 | /* | 134 | /* |
135 | * bind.c | 135 | * bind.c |
136 | */ | 136 | */ |
137 | extern int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args); | 137 | extern int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args); |
138 | extern void cachefiles_daemon_unbind(struct cachefiles_cache *cache); | 138 | extern void cachefiles_daemon_unbind(struct cachefiles_cache *cache); |
139 | 139 | ||
140 | /* | 140 | /* |
141 | * daemon.c | 141 | * daemon.c |
142 | */ | 142 | */ |
143 | extern const struct file_operations cachefiles_daemon_fops; | 143 | extern const struct file_operations cachefiles_daemon_fops; |
144 | 144 | ||
145 | extern int cachefiles_has_space(struct cachefiles_cache *cache, | 145 | extern int cachefiles_has_space(struct cachefiles_cache *cache, |
146 | unsigned fnr, unsigned bnr); | 146 | unsigned fnr, unsigned bnr); |
147 | 147 | ||
148 | /* | 148 | /* |
149 | * interface.c | 149 | * interface.c |
150 | */ | 150 | */ |
151 | extern const struct fscache_cache_ops cachefiles_cache_ops; | 151 | extern const struct fscache_cache_ops cachefiles_cache_ops; |
152 | 152 | ||
153 | /* | 153 | /* |
154 | * key.c | 154 | * key.c |
155 | */ | 155 | */ |
156 | extern char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type); | 156 | extern char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type); |
157 | 157 | ||
158 | /* | 158 | /* |
159 | * namei.c | 159 | * namei.c |
160 | */ | 160 | */ |
161 | extern int cachefiles_delete_object(struct cachefiles_cache *cache, | 161 | extern int cachefiles_delete_object(struct cachefiles_cache *cache, |
162 | struct cachefiles_object *object); | 162 | struct cachefiles_object *object); |
163 | extern int cachefiles_walk_to_object(struct cachefiles_object *parent, | 163 | extern int cachefiles_walk_to_object(struct cachefiles_object *parent, |
164 | struct cachefiles_object *object, | 164 | struct cachefiles_object *object, |
165 | const char *key, | 165 | const char *key, |
166 | struct cachefiles_xattr *auxdata); | 166 | struct cachefiles_xattr *auxdata); |
167 | extern struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, | 167 | extern struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, |
168 | struct dentry *dir, | 168 | struct dentry *dir, |
169 | const char *name); | 169 | const char *name); |
170 | 170 | ||
171 | extern int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, | 171 | extern int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, |
172 | char *filename); | 172 | char *filename); |
173 | 173 | ||
174 | extern int cachefiles_check_in_use(struct cachefiles_cache *cache, | 174 | extern int cachefiles_check_in_use(struct cachefiles_cache *cache, |
175 | struct dentry *dir, char *filename); | 175 | struct dentry *dir, char *filename); |
176 | 176 | ||
177 | /* | 177 | /* |
178 | * proc.c | 178 | * proc.c |
179 | */ | 179 | */ |
180 | #ifdef CONFIG_CACHEFILES_HISTOGRAM | 180 | #ifdef CONFIG_CACHEFILES_HISTOGRAM |
181 | extern atomic_t cachefiles_lookup_histogram[HZ]; | 181 | extern atomic_t cachefiles_lookup_histogram[HZ]; |
182 | extern atomic_t cachefiles_mkdir_histogram[HZ]; | 182 | extern atomic_t cachefiles_mkdir_histogram[HZ]; |
183 | extern atomic_t cachefiles_create_histogram[HZ]; | 183 | extern atomic_t cachefiles_create_histogram[HZ]; |
184 | 184 | ||
185 | extern int __init cachefiles_proc_init(void); | 185 | extern int __init cachefiles_proc_init(void); |
186 | extern void cachefiles_proc_cleanup(void); | 186 | extern void cachefiles_proc_cleanup(void); |
187 | static inline | 187 | static inline |
188 | void cachefiles_hist(atomic_t histogram[], unsigned long start_jif) | 188 | void cachefiles_hist(atomic_t histogram[], unsigned long start_jif) |
189 | { | 189 | { |
190 | unsigned long jif = jiffies - start_jif; | 190 | unsigned long jif = jiffies - start_jif; |
191 | if (jif >= HZ) | 191 | if (jif >= HZ) |
192 | jif = HZ - 1; | 192 | jif = HZ - 1; |
193 | atomic_inc(&histogram[jif]); | 193 | atomic_inc(&histogram[jif]); |
194 | } | 194 | } |
195 | 195 | ||
196 | #else | 196 | #else |
197 | #define cachefiles_proc_init() (0) | 197 | #define cachefiles_proc_init() (0) |
198 | #define cachefiles_proc_cleanup() do {} while (0) | 198 | #define cachefiles_proc_cleanup() do {} while (0) |
199 | #define cachefiles_hist(hist, start_jif) do {} while (0) | 199 | #define cachefiles_hist(hist, start_jif) do {} while (0) |
200 | #endif | 200 | #endif |
201 | 201 | ||
202 | /* | 202 | /* |
203 | * rdwr.c | 203 | * rdwr.c |
204 | */ | 204 | */ |
205 | extern int cachefiles_read_or_alloc_page(struct fscache_retrieval *, | 205 | extern int cachefiles_read_or_alloc_page(struct fscache_retrieval *, |
206 | struct page *, gfp_t); | 206 | struct page *, gfp_t); |
207 | extern int cachefiles_read_or_alloc_pages(struct fscache_retrieval *, | 207 | extern int cachefiles_read_or_alloc_pages(struct fscache_retrieval *, |
208 | struct list_head *, unsigned *, | 208 | struct list_head *, unsigned *, |
209 | gfp_t); | 209 | gfp_t); |
210 | extern int cachefiles_allocate_page(struct fscache_retrieval *, struct page *, | 210 | extern int cachefiles_allocate_page(struct fscache_retrieval *, struct page *, |
211 | gfp_t); | 211 | gfp_t); |
212 | extern int cachefiles_allocate_pages(struct fscache_retrieval *, | 212 | extern int cachefiles_allocate_pages(struct fscache_retrieval *, |
213 | struct list_head *, unsigned *, gfp_t); | 213 | struct list_head *, unsigned *, gfp_t); |
214 | extern int cachefiles_write_page(struct fscache_storage *, struct page *); | 214 | extern int cachefiles_write_page(struct fscache_storage *, struct page *); |
215 | extern void cachefiles_uncache_page(struct fscache_object *, struct page *); | 215 | extern void cachefiles_uncache_page(struct fscache_object *, struct page *); |
216 | 216 | ||
217 | /* | 217 | /* |
218 | * security.c | 218 | * security.c |
219 | */ | 219 | */ |
220 | extern int cachefiles_get_security_ID(struct cachefiles_cache *cache); | 220 | extern int cachefiles_get_security_ID(struct cachefiles_cache *cache); |
221 | extern int cachefiles_determine_cache_security(struct cachefiles_cache *cache, | 221 | extern int cachefiles_determine_cache_security(struct cachefiles_cache *cache, |
222 | struct dentry *root, | 222 | struct dentry *root, |
223 | const struct cred **_saved_cred); | 223 | const struct cred **_saved_cred); |
224 | 224 | ||
225 | static inline void cachefiles_begin_secure(struct cachefiles_cache *cache, | 225 | static inline void cachefiles_begin_secure(struct cachefiles_cache *cache, |
226 | const struct cred **_saved_cred) | 226 | const struct cred **_saved_cred) |
227 | { | 227 | { |
228 | *_saved_cred = override_creds(cache->cache_cred); | 228 | *_saved_cred = override_creds(cache->cache_cred); |
229 | } | 229 | } |
230 | 230 | ||
231 | static inline void cachefiles_end_secure(struct cachefiles_cache *cache, | 231 | static inline void cachefiles_end_secure(struct cachefiles_cache *cache, |
232 | const struct cred *saved_cred) | 232 | const struct cred *saved_cred) |
233 | { | 233 | { |
234 | revert_creds(saved_cred); | 234 | revert_creds(saved_cred); |
235 | } | 235 | } |
236 | 236 | ||
237 | /* | 237 | /* |
238 | * xattr.c | 238 | * xattr.c |
239 | */ | 239 | */ |
240 | extern int cachefiles_check_object_type(struct cachefiles_object *object); | 240 | extern int cachefiles_check_object_type(struct cachefiles_object *object); |
241 | extern int cachefiles_set_object_xattr(struct cachefiles_object *object, | 241 | extern int cachefiles_set_object_xattr(struct cachefiles_object *object, |
242 | struct cachefiles_xattr *auxdata); | 242 | struct cachefiles_xattr *auxdata); |
243 | extern int cachefiles_update_object_xattr(struct cachefiles_object *object, | 243 | extern int cachefiles_update_object_xattr(struct cachefiles_object *object, |
244 | struct cachefiles_xattr *auxdata); | 244 | struct cachefiles_xattr *auxdata); |
245 | extern int cachefiles_check_auxdata(struct cachefiles_object *object); | 245 | extern int cachefiles_check_auxdata(struct cachefiles_object *object); |
246 | extern int cachefiles_check_object_xattr(struct cachefiles_object *object, | 246 | extern int cachefiles_check_object_xattr(struct cachefiles_object *object, |
247 | struct cachefiles_xattr *auxdata); | 247 | struct cachefiles_xattr *auxdata); |
248 | extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache, | 248 | extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache, |
249 | struct dentry *dentry); | 249 | struct dentry *dentry); |
250 | 250 | ||
251 | 251 | ||
252 | /* | 252 | /* |
253 | * error handling | 253 | * error handling |
254 | */ | 254 | */ |
255 | 255 | ||
256 | #define cachefiles_io_error(___cache, FMT, ...) \ | 256 | #define cachefiles_io_error(___cache, FMT, ...) \ |
257 | do { \ | 257 | do { \ |
258 | pr_err("I/O Error: " FMT, ##__VA_ARGS__); \ | 258 | pr_err("I/O Error: " FMT"\n", ##__VA_ARGS__); \ |
259 | fscache_io_error(&(___cache)->cache); \ | 259 | fscache_io_error(&(___cache)->cache); \ |
260 | set_bit(CACHEFILES_DEAD, &(___cache)->flags); \ | 260 | set_bit(CACHEFILES_DEAD, &(___cache)->flags); \ |
261 | } while (0) | 261 | } while (0) |
262 | 262 | ||
263 | #define cachefiles_io_error_obj(object, FMT, ...) \ | 263 | #define cachefiles_io_error_obj(object, FMT, ...) \ |
264 | do { \ | 264 | do { \ |
265 | struct cachefiles_cache *___cache; \ | 265 | struct cachefiles_cache *___cache; \ |
266 | \ | 266 | \ |
267 | ___cache = container_of((object)->fscache.cache, \ | 267 | ___cache = container_of((object)->fscache.cache, \ |
268 | struct cachefiles_cache, cache); \ | 268 | struct cachefiles_cache, cache); \ |
269 | cachefiles_io_error(___cache, FMT, ##__VA_ARGS__); \ | 269 | cachefiles_io_error(___cache, FMT, ##__VA_ARGS__); \ |
270 | } while (0) | 270 | } while (0) |
271 | 271 | ||
272 | 272 | ||
273 | /* | 273 | /* |
274 | * debug tracing | 274 | * debug tracing |
275 | */ | 275 | */ |
276 | #define dbgprintk(FMT, ...) \ | 276 | #define dbgprintk(FMT, ...) \ |
277 | printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__) | 277 | printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__) |
278 | 278 | ||
279 | #define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__) | 279 | #define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__) |
280 | #define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__) | 280 | #define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__) |
281 | #define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__) | 281 | #define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__) |
282 | 282 | ||
283 | 283 | ||
284 | #if defined(__KDEBUG) | 284 | #if defined(__KDEBUG) |
285 | #define _enter(FMT, ...) kenter(FMT, ##__VA_ARGS__) | 285 | #define _enter(FMT, ...) kenter(FMT, ##__VA_ARGS__) |
286 | #define _leave(FMT, ...) kleave(FMT, ##__VA_ARGS__) | 286 | #define _leave(FMT, ...) kleave(FMT, ##__VA_ARGS__) |
287 | #define _debug(FMT, ...) kdebug(FMT, ##__VA_ARGS__) | 287 | #define _debug(FMT, ...) kdebug(FMT, ##__VA_ARGS__) |
288 | 288 | ||
289 | #elif defined(CONFIG_CACHEFILES_DEBUG) | 289 | #elif defined(CONFIG_CACHEFILES_DEBUG) |
290 | #define _enter(FMT, ...) \ | 290 | #define _enter(FMT, ...) \ |
291 | do { \ | 291 | do { \ |
292 | if (cachefiles_debug & CACHEFILES_DEBUG_KENTER) \ | 292 | if (cachefiles_debug & CACHEFILES_DEBUG_KENTER) \ |
293 | kenter(FMT, ##__VA_ARGS__); \ | 293 | kenter(FMT, ##__VA_ARGS__); \ |
294 | } while (0) | 294 | } while (0) |
295 | 295 | ||
296 | #define _leave(FMT, ...) \ | 296 | #define _leave(FMT, ...) \ |
297 | do { \ | 297 | do { \ |
298 | if (cachefiles_debug & CACHEFILES_DEBUG_KLEAVE) \ | 298 | if (cachefiles_debug & CACHEFILES_DEBUG_KLEAVE) \ |
299 | kleave(FMT, ##__VA_ARGS__); \ | 299 | kleave(FMT, ##__VA_ARGS__); \ |
300 | } while (0) | 300 | } while (0) |
301 | 301 | ||
302 | #define _debug(FMT, ...) \ | 302 | #define _debug(FMT, ...) \ |
303 | do { \ | 303 | do { \ |
304 | if (cachefiles_debug & CACHEFILES_DEBUG_KDEBUG) \ | 304 | if (cachefiles_debug & CACHEFILES_DEBUG_KDEBUG) \ |
305 | kdebug(FMT, ##__VA_ARGS__); \ | 305 | kdebug(FMT, ##__VA_ARGS__); \ |
306 | } while (0) | 306 | } while (0) |
307 | 307 | ||
308 | #else | 308 | #else |
309 | #define _enter(FMT, ...) no_printk("==> %s("FMT")", __func__, ##__VA_ARGS__) | 309 | #define _enter(FMT, ...) no_printk("==> %s("FMT")", __func__, ##__VA_ARGS__) |
310 | #define _leave(FMT, ...) no_printk("<== %s()"FMT"", __func__, ##__VA_ARGS__) | 310 | #define _leave(FMT, ...) no_printk("<== %s()"FMT"", __func__, ##__VA_ARGS__) |
311 | #define _debug(FMT, ...) no_printk(FMT, ##__VA_ARGS__) | 311 | #define _debug(FMT, ...) no_printk(FMT, ##__VA_ARGS__) |
312 | #endif | 312 | #endif |
313 | 313 | ||
314 | #if 1 /* defined(__KDEBUGALL) */ | 314 | #if 1 /* defined(__KDEBUGALL) */ |
315 | 315 | ||
316 | #define ASSERT(X) \ | 316 | #define ASSERT(X) \ |
317 | do { \ | 317 | do { \ |
318 | if (unlikely(!(X))) { \ | 318 | if (unlikely(!(X))) { \ |
319 | pr_err("\n"); \ | 319 | pr_err("\n"); \ |
320 | pr_err("Assertion failed\n"); \ | 320 | pr_err("Assertion failed\n"); \ |
321 | BUG(); \ | 321 | BUG(); \ |
322 | } \ | 322 | } \ |
323 | } while (0) | 323 | } while (0) |
324 | 324 | ||
325 | #define ASSERTCMP(X, OP, Y) \ | 325 | #define ASSERTCMP(X, OP, Y) \ |
326 | do { \ | 326 | do { \ |
327 | if (unlikely(!((X) OP (Y)))) { \ | 327 | if (unlikely(!((X) OP (Y)))) { \ |
328 | pr_err("\n"); \ | 328 | pr_err("\n"); \ |
329 | pr_err("Assertion failed\n"); \ | 329 | pr_err("Assertion failed\n"); \ |
330 | pr_err("%lx " #OP " %lx is false\n", \ | 330 | pr_err("%lx " #OP " %lx is false\n", \ |
331 | (unsigned long)(X), (unsigned long)(Y)); \ | 331 | (unsigned long)(X), (unsigned long)(Y)); \ |
332 | BUG(); \ | 332 | BUG(); \ |
333 | } \ | 333 | } \ |
334 | } while (0) | 334 | } while (0) |
335 | 335 | ||
336 | #define ASSERTIF(C, X) \ | 336 | #define ASSERTIF(C, X) \ |
337 | do { \ | 337 | do { \ |
338 | if (unlikely((C) && !(X))) { \ | 338 | if (unlikely((C) && !(X))) { \ |
339 | pr_err("\n"); \ | 339 | pr_err("\n"); \ |
340 | pr_err("Assertion failed\n"); \ | 340 | pr_err("Assertion failed\n"); \ |
341 | BUG(); \ | 341 | BUG(); \ |
342 | } \ | 342 | } \ |
343 | } while (0) | 343 | } while (0) |
344 | 344 | ||
345 | #define ASSERTIFCMP(C, X, OP, Y) \ | 345 | #define ASSERTIFCMP(C, X, OP, Y) \ |
346 | do { \ | 346 | do { \ |
347 | if (unlikely((C) && !((X) OP (Y)))) { \ | 347 | if (unlikely((C) && !((X) OP (Y)))) { \ |
348 | pr_err("\n"); \ | 348 | pr_err("\n"); \ |
349 | pr_err("Assertion failed\n"); \ | 349 | pr_err("Assertion failed\n"); \ |
350 | pr_err("%lx " #OP " %lx is false\n", \ | 350 | pr_err("%lx " #OP " %lx is false\n", \ |
351 | (unsigned long)(X), (unsigned long)(Y)); \ | 351 | (unsigned long)(X), (unsigned long)(Y)); \ |
352 | BUG(); \ | 352 | BUG(); \ |
353 | } \ | 353 | } \ |
354 | } while (0) | 354 | } while (0) |
355 | 355 | ||
356 | #else | 356 | #else |
357 | 357 | ||
358 | #define ASSERT(X) do {} while (0) | 358 | #define ASSERT(X) do {} while (0) |
359 | #define ASSERTCMP(X, OP, Y) do {} while (0) | 359 | #define ASSERTCMP(X, OP, Y) do {} while (0) |
360 | #define ASSERTIF(C, X) do {} while (0) | 360 | #define ASSERTIF(C, X) do {} while (0) |
361 | #define ASSERTIFCMP(C, X, OP, Y) do {} while (0) | 361 | #define ASSERTIFCMP(C, X, OP, Y) do {} while (0) |
362 | 362 | ||
363 | #endif | 363 | #endif |
364 | 364 |
fs/cachefiles/main.c
1 | /* Network filesystem caching backend to use cache files on a premounted | 1 | /* Network filesystem caching backend to use cache files on a premounted |
2 | * filesystem | 2 | * filesystem |
3 | * | 3 | * |
4 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | 4 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) | 5 | * Written by David Howells (dhowells@redhat.com) |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public Licence | 8 | * modify it under the terms of the GNU General Public Licence |
9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
10 | * 2 of the Licence, or (at your option) any later version. | 10 | * 2 of the Licence, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/completion.h> | 16 | #include <linux/completion.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/file.h> | 19 | #include <linux/file.h> |
20 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
21 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
22 | #include <linux/statfs.h> | 22 | #include <linux/statfs.h> |
23 | #include <linux/sysctl.h> | 23 | #include <linux/sysctl.h> |
24 | #include <linux/miscdevice.h> | 24 | #include <linux/miscdevice.h> |
25 | #include "internal.h" | 25 | #include "internal.h" |
26 | 26 | ||
27 | unsigned cachefiles_debug; | 27 | unsigned cachefiles_debug; |
28 | module_param_named(debug, cachefiles_debug, uint, S_IWUSR | S_IRUGO); | 28 | module_param_named(debug, cachefiles_debug, uint, S_IWUSR | S_IRUGO); |
29 | MODULE_PARM_DESC(cachefiles_debug, "CacheFiles debugging mask"); | 29 | MODULE_PARM_DESC(cachefiles_debug, "CacheFiles debugging mask"); |
30 | 30 | ||
31 | MODULE_DESCRIPTION("Mounted-filesystem based cache"); | 31 | MODULE_DESCRIPTION("Mounted-filesystem based cache"); |
32 | MODULE_AUTHOR("Red Hat, Inc."); | 32 | MODULE_AUTHOR("Red Hat, Inc."); |
33 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
34 | 34 | ||
35 | struct kmem_cache *cachefiles_object_jar; | 35 | struct kmem_cache *cachefiles_object_jar; |
36 | 36 | ||
37 | static struct miscdevice cachefiles_dev = { | 37 | static struct miscdevice cachefiles_dev = { |
38 | .minor = MISC_DYNAMIC_MINOR, | 38 | .minor = MISC_DYNAMIC_MINOR, |
39 | .name = "cachefiles", | 39 | .name = "cachefiles", |
40 | .fops = &cachefiles_daemon_fops, | 40 | .fops = &cachefiles_daemon_fops, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | static void cachefiles_object_init_once(void *_object) | 43 | static void cachefiles_object_init_once(void *_object) |
44 | { | 44 | { |
45 | struct cachefiles_object *object = _object; | 45 | struct cachefiles_object *object = _object; |
46 | 46 | ||
47 | memset(object, 0, sizeof(*object)); | 47 | memset(object, 0, sizeof(*object)); |
48 | spin_lock_init(&object->work_lock); | 48 | spin_lock_init(&object->work_lock); |
49 | } | 49 | } |
50 | 50 | ||
51 | /* | 51 | /* |
52 | * initialise the fs caching module | 52 | * initialise the fs caching module |
53 | */ | 53 | */ |
54 | static int __init cachefiles_init(void) | 54 | static int __init cachefiles_init(void) |
55 | { | 55 | { |
56 | int ret; | 56 | int ret; |
57 | 57 | ||
58 | ret = misc_register(&cachefiles_dev); | 58 | ret = misc_register(&cachefiles_dev); |
59 | if (ret < 0) | 59 | if (ret < 0) |
60 | goto error_dev; | 60 | goto error_dev; |
61 | 61 | ||
62 | /* create an object jar */ | 62 | /* create an object jar */ |
63 | ret = -ENOMEM; | 63 | ret = -ENOMEM; |
64 | cachefiles_object_jar = | 64 | cachefiles_object_jar = |
65 | kmem_cache_create("cachefiles_object_jar", | 65 | kmem_cache_create("cachefiles_object_jar", |
66 | sizeof(struct cachefiles_object), | 66 | sizeof(struct cachefiles_object), |
67 | 0, | 67 | 0, |
68 | SLAB_HWCACHE_ALIGN, | 68 | SLAB_HWCACHE_ALIGN, |
69 | cachefiles_object_init_once); | 69 | cachefiles_object_init_once); |
70 | if (!cachefiles_object_jar) { | 70 | if (!cachefiles_object_jar) { |
71 | pr_notice("Failed to allocate an object jar\n"); | 71 | pr_notice("Failed to allocate an object jar\n"); |
72 | goto error_object_jar; | 72 | goto error_object_jar; |
73 | } | 73 | } |
74 | 74 | ||
75 | ret = cachefiles_proc_init(); | 75 | ret = cachefiles_proc_init(); |
76 | if (ret < 0) | 76 | if (ret < 0) |
77 | goto error_proc; | 77 | goto error_proc; |
78 | 78 | ||
79 | pr_info("Loaded\n"); | 79 | pr_info("Loaded\n"); |
80 | return 0; | 80 | return 0; |
81 | 81 | ||
82 | error_proc: | 82 | error_proc: |
83 | kmem_cache_destroy(cachefiles_object_jar); | 83 | kmem_cache_destroy(cachefiles_object_jar); |
84 | error_object_jar: | 84 | error_object_jar: |
85 | misc_deregister(&cachefiles_dev); | 85 | misc_deregister(&cachefiles_dev); |
86 | error_dev: | 86 | error_dev: |
87 | pr_err("failed to register: %d", ret); | 87 | pr_err("failed to register: %d\n", ret); |
88 | return ret; | 88 | return ret; |
89 | } | 89 | } |
90 | 90 | ||
91 | fs_initcall(cachefiles_init); | 91 | fs_initcall(cachefiles_init); |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * clean up on module removal | 94 | * clean up on module removal |
95 | */ | 95 | */ |
96 | static void __exit cachefiles_exit(void) | 96 | static void __exit cachefiles_exit(void) |
97 | { | 97 | { |
98 | pr_info("Unloading\n"); | 98 | pr_info("Unloading\n"); |
99 | 99 | ||
100 | cachefiles_proc_cleanup(); | 100 | cachefiles_proc_cleanup(); |
101 | kmem_cache_destroy(cachefiles_object_jar); | 101 | kmem_cache_destroy(cachefiles_object_jar); |
102 | misc_deregister(&cachefiles_dev); | 102 | misc_deregister(&cachefiles_dev); |
103 | } | 103 | } |
104 | 104 | ||
105 | module_exit(cachefiles_exit); | 105 | module_exit(cachefiles_exit); |
106 | 106 |
fs/cachefiles/namei.c
1 | /* CacheFiles path walking and related routines | 1 | /* CacheFiles path walking and related routines |
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/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/file.h> | 14 | #include <linux/file.h> |
15 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
16 | #include <linux/fsnotify.h> | 16 | #include <linux/fsnotify.h> |
17 | #include <linux/quotaops.h> | 17 | #include <linux/quotaops.h> |
18 | #include <linux/xattr.h> | 18 | #include <linux/xattr.h> |
19 | #include <linux/mount.h> | 19 | #include <linux/mount.h> |
20 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
21 | #include <linux/security.h> | 21 | #include <linux/security.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include "internal.h" | 23 | #include "internal.h" |
24 | 24 | ||
25 | #define CACHEFILES_KEYBUF_SIZE 512 | 25 | #define CACHEFILES_KEYBUF_SIZE 512 |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * dump debugging info about an object | 28 | * dump debugging info about an object |
29 | */ | 29 | */ |
30 | static noinline | 30 | static noinline |
31 | void __cachefiles_printk_object(struct cachefiles_object *object, | 31 | void __cachefiles_printk_object(struct cachefiles_object *object, |
32 | const char *prefix, | 32 | const char *prefix, |
33 | u8 *keybuf) | 33 | u8 *keybuf) |
34 | { | 34 | { |
35 | struct fscache_cookie *cookie; | 35 | struct fscache_cookie *cookie; |
36 | unsigned keylen, loop; | 36 | unsigned keylen, loop; |
37 | 37 | ||
38 | pr_err("%sobject: OBJ%x\n", prefix, object->fscache.debug_id); | 38 | pr_err("%sobject: OBJ%x\n", prefix, object->fscache.debug_id); |
39 | pr_err("%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n", | 39 | pr_err("%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n", |
40 | prefix, object->fscache.state->name, | 40 | prefix, object->fscache.state->name, |
41 | object->fscache.flags, work_busy(&object->fscache.work), | 41 | object->fscache.flags, work_busy(&object->fscache.work), |
42 | object->fscache.events, object->fscache.event_mask); | 42 | object->fscache.events, object->fscache.event_mask); |
43 | pr_err("%sops=%u inp=%u exc=%u\n", | 43 | pr_err("%sops=%u inp=%u exc=%u\n", |
44 | prefix, object->fscache.n_ops, object->fscache.n_in_progress, | 44 | prefix, object->fscache.n_ops, object->fscache.n_in_progress, |
45 | object->fscache.n_exclusive); | 45 | object->fscache.n_exclusive); |
46 | pr_err("%sparent=%p\n", | 46 | pr_err("%sparent=%p\n", |
47 | prefix, object->fscache.parent); | 47 | prefix, object->fscache.parent); |
48 | 48 | ||
49 | spin_lock(&object->fscache.lock); | 49 | spin_lock(&object->fscache.lock); |
50 | cookie = object->fscache.cookie; | 50 | cookie = object->fscache.cookie; |
51 | if (cookie) { | 51 | if (cookie) { |
52 | pr_err("%scookie=%p [pr=%p nd=%p fl=%lx]\n", | 52 | pr_err("%scookie=%p [pr=%p nd=%p fl=%lx]\n", |
53 | prefix, | 53 | prefix, |
54 | object->fscache.cookie, | 54 | object->fscache.cookie, |
55 | object->fscache.cookie->parent, | 55 | object->fscache.cookie->parent, |
56 | object->fscache.cookie->netfs_data, | 56 | object->fscache.cookie->netfs_data, |
57 | object->fscache.cookie->flags); | 57 | object->fscache.cookie->flags); |
58 | if (keybuf && cookie->def) | 58 | if (keybuf && cookie->def) |
59 | keylen = cookie->def->get_key(cookie->netfs_data, keybuf, | 59 | keylen = cookie->def->get_key(cookie->netfs_data, keybuf, |
60 | CACHEFILES_KEYBUF_SIZE); | 60 | CACHEFILES_KEYBUF_SIZE); |
61 | else | 61 | else |
62 | keylen = 0; | 62 | keylen = 0; |
63 | } else { | 63 | } else { |
64 | pr_err("%scookie=NULL\n", prefix); | 64 | pr_err("%scookie=NULL\n", prefix); |
65 | keylen = 0; | 65 | keylen = 0; |
66 | } | 66 | } |
67 | spin_unlock(&object->fscache.lock); | 67 | spin_unlock(&object->fscache.lock); |
68 | 68 | ||
69 | if (keylen) { | 69 | if (keylen) { |
70 | pr_err("%skey=[%u] '", prefix, keylen); | 70 | pr_err("%skey=[%u] '", prefix, keylen); |
71 | for (loop = 0; loop < keylen; loop++) | 71 | for (loop = 0; loop < keylen; loop++) |
72 | pr_cont("%02x", keybuf[loop]); | 72 | pr_cont("%02x", keybuf[loop]); |
73 | pr_cont("'\n"); | 73 | pr_cont("'\n"); |
74 | } | 74 | } |
75 | } | 75 | } |
76 | 76 | ||
77 | /* | 77 | /* |
78 | * dump debugging info about a pair of objects | 78 | * dump debugging info about a pair of objects |
79 | */ | 79 | */ |
80 | static noinline void cachefiles_printk_object(struct cachefiles_object *object, | 80 | static noinline void cachefiles_printk_object(struct cachefiles_object *object, |
81 | struct cachefiles_object *xobject) | 81 | struct cachefiles_object *xobject) |
82 | { | 82 | { |
83 | u8 *keybuf; | 83 | u8 *keybuf; |
84 | 84 | ||
85 | keybuf = kmalloc(CACHEFILES_KEYBUF_SIZE, GFP_NOIO); | 85 | keybuf = kmalloc(CACHEFILES_KEYBUF_SIZE, GFP_NOIO); |
86 | if (object) | 86 | if (object) |
87 | __cachefiles_printk_object(object, "", keybuf); | 87 | __cachefiles_printk_object(object, "", keybuf); |
88 | if (xobject) | 88 | if (xobject) |
89 | __cachefiles_printk_object(xobject, "x", keybuf); | 89 | __cachefiles_printk_object(xobject, "x", keybuf); |
90 | kfree(keybuf); | 90 | kfree(keybuf); |
91 | } | 91 | } |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * mark the owner of a dentry, if there is one, to indicate that that dentry | 94 | * mark the owner of a dentry, if there is one, to indicate that that dentry |
95 | * has been preemptively deleted | 95 | * has been preemptively deleted |
96 | * - the caller must hold the i_mutex on the dentry's parent as required to | 96 | * - the caller must hold the i_mutex on the dentry's parent as required to |
97 | * call vfs_unlink(), vfs_rmdir() or vfs_rename() | 97 | * call vfs_unlink(), vfs_rmdir() or vfs_rename() |
98 | */ | 98 | */ |
99 | static void cachefiles_mark_object_buried(struct cachefiles_cache *cache, | 99 | static void cachefiles_mark_object_buried(struct cachefiles_cache *cache, |
100 | struct dentry *dentry) | 100 | struct dentry *dentry) |
101 | { | 101 | { |
102 | struct cachefiles_object *object; | 102 | struct cachefiles_object *object; |
103 | struct rb_node *p; | 103 | struct rb_node *p; |
104 | 104 | ||
105 | _enter(",'%*.*s'", | 105 | _enter(",'%*.*s'", |
106 | dentry->d_name.len, dentry->d_name.len, dentry->d_name.name); | 106 | dentry->d_name.len, dentry->d_name.len, dentry->d_name.name); |
107 | 107 | ||
108 | write_lock(&cache->active_lock); | 108 | write_lock(&cache->active_lock); |
109 | 109 | ||
110 | p = cache->active_nodes.rb_node; | 110 | p = cache->active_nodes.rb_node; |
111 | while (p) { | 111 | while (p) { |
112 | object = rb_entry(p, struct cachefiles_object, active_node); | 112 | object = rb_entry(p, struct cachefiles_object, active_node); |
113 | if (object->dentry > dentry) | 113 | if (object->dentry > dentry) |
114 | p = p->rb_left; | 114 | p = p->rb_left; |
115 | else if (object->dentry < dentry) | 115 | else if (object->dentry < dentry) |
116 | p = p->rb_right; | 116 | p = p->rb_right; |
117 | else | 117 | else |
118 | goto found_dentry; | 118 | goto found_dentry; |
119 | } | 119 | } |
120 | 120 | ||
121 | write_unlock(&cache->active_lock); | 121 | write_unlock(&cache->active_lock); |
122 | _leave(" [no owner]"); | 122 | _leave(" [no owner]"); |
123 | return; | 123 | return; |
124 | 124 | ||
125 | /* found the dentry for */ | 125 | /* found the dentry for */ |
126 | found_dentry: | 126 | found_dentry: |
127 | kdebug("preemptive burial: OBJ%x [%s] %p", | 127 | kdebug("preemptive burial: OBJ%x [%s] %p", |
128 | object->fscache.debug_id, | 128 | object->fscache.debug_id, |
129 | object->fscache.state->name, | 129 | object->fscache.state->name, |
130 | dentry); | 130 | dentry); |
131 | 131 | ||
132 | if (fscache_object_is_live(&object->fscache)) { | 132 | if (fscache_object_is_live(&object->fscache)) { |
133 | pr_err("\n"); | 133 | pr_err("\n"); |
134 | pr_err("Error: Can't preemptively bury live object\n"); | 134 | pr_err("Error: Can't preemptively bury live object\n"); |
135 | cachefiles_printk_object(object, NULL); | 135 | cachefiles_printk_object(object, NULL); |
136 | } else if (test_and_set_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { | 136 | } else if (test_and_set_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { |
137 | pr_err("Error: Object already preemptively buried\n"); | 137 | pr_err("Error: Object already preemptively buried\n"); |
138 | } | 138 | } |
139 | 139 | ||
140 | write_unlock(&cache->active_lock); | 140 | write_unlock(&cache->active_lock); |
141 | _leave(" [owner marked]"); | 141 | _leave(" [owner marked]"); |
142 | } | 142 | } |
143 | 143 | ||
144 | /* | 144 | /* |
145 | * record the fact that an object is now active | 145 | * record the fact that an object is now active |
146 | */ | 146 | */ |
147 | static int cachefiles_mark_object_active(struct cachefiles_cache *cache, | 147 | static int cachefiles_mark_object_active(struct cachefiles_cache *cache, |
148 | struct cachefiles_object *object) | 148 | struct cachefiles_object *object) |
149 | { | 149 | { |
150 | struct cachefiles_object *xobject; | 150 | struct cachefiles_object *xobject; |
151 | struct rb_node **_p, *_parent = NULL; | 151 | struct rb_node **_p, *_parent = NULL; |
152 | struct dentry *dentry; | 152 | struct dentry *dentry; |
153 | 153 | ||
154 | _enter(",%p", object); | 154 | _enter(",%p", object); |
155 | 155 | ||
156 | try_again: | 156 | try_again: |
157 | write_lock(&cache->active_lock); | 157 | write_lock(&cache->active_lock); |
158 | 158 | ||
159 | if (test_and_set_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) { | 159 | if (test_and_set_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) { |
160 | pr_err("Error: Object already active\n"); | 160 | pr_err("Error: Object already active\n"); |
161 | cachefiles_printk_object(object, NULL); | 161 | cachefiles_printk_object(object, NULL); |
162 | BUG(); | 162 | BUG(); |
163 | } | 163 | } |
164 | 164 | ||
165 | dentry = object->dentry; | 165 | dentry = object->dentry; |
166 | _p = &cache->active_nodes.rb_node; | 166 | _p = &cache->active_nodes.rb_node; |
167 | while (*_p) { | 167 | while (*_p) { |
168 | _parent = *_p; | 168 | _parent = *_p; |
169 | xobject = rb_entry(_parent, | 169 | xobject = rb_entry(_parent, |
170 | struct cachefiles_object, active_node); | 170 | struct cachefiles_object, active_node); |
171 | 171 | ||
172 | ASSERT(xobject != object); | 172 | ASSERT(xobject != object); |
173 | 173 | ||
174 | if (xobject->dentry > dentry) | 174 | if (xobject->dentry > dentry) |
175 | _p = &(*_p)->rb_left; | 175 | _p = &(*_p)->rb_left; |
176 | else if (xobject->dentry < dentry) | 176 | else if (xobject->dentry < dentry) |
177 | _p = &(*_p)->rb_right; | 177 | _p = &(*_p)->rb_right; |
178 | else | 178 | else |
179 | goto wait_for_old_object; | 179 | goto wait_for_old_object; |
180 | } | 180 | } |
181 | 181 | ||
182 | rb_link_node(&object->active_node, _parent, _p); | 182 | rb_link_node(&object->active_node, _parent, _p); |
183 | rb_insert_color(&object->active_node, &cache->active_nodes); | 183 | rb_insert_color(&object->active_node, &cache->active_nodes); |
184 | 184 | ||
185 | write_unlock(&cache->active_lock); | 185 | write_unlock(&cache->active_lock); |
186 | _leave(" = 0"); | 186 | _leave(" = 0"); |
187 | return 0; | 187 | return 0; |
188 | 188 | ||
189 | /* an old object from a previous incarnation is hogging the slot - we | 189 | /* an old object from a previous incarnation is hogging the slot - we |
190 | * need to wait for it to be destroyed */ | 190 | * need to wait for it to be destroyed */ |
191 | wait_for_old_object: | 191 | wait_for_old_object: |
192 | if (fscache_object_is_live(&object->fscache)) { | 192 | if (fscache_object_is_live(&object->fscache)) { |
193 | pr_err("\n"); | 193 | pr_err("\n"); |
194 | pr_err("Error: Unexpected object collision\n"); | 194 | pr_err("Error: Unexpected object collision\n"); |
195 | cachefiles_printk_object(object, xobject); | 195 | cachefiles_printk_object(object, xobject); |
196 | BUG(); | 196 | BUG(); |
197 | } | 197 | } |
198 | atomic_inc(&xobject->usage); | 198 | atomic_inc(&xobject->usage); |
199 | write_unlock(&cache->active_lock); | 199 | write_unlock(&cache->active_lock); |
200 | 200 | ||
201 | if (test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { | 201 | if (test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { |
202 | wait_queue_head_t *wq; | 202 | wait_queue_head_t *wq; |
203 | 203 | ||
204 | signed long timeout = 60 * HZ; | 204 | signed long timeout = 60 * HZ; |
205 | wait_queue_t wait; | 205 | wait_queue_t wait; |
206 | bool requeue; | 206 | bool requeue; |
207 | 207 | ||
208 | /* if the object we're waiting for is queued for processing, | 208 | /* if the object we're waiting for is queued for processing, |
209 | * then just put ourselves on the queue behind it */ | 209 | * then just put ourselves on the queue behind it */ |
210 | if (work_pending(&xobject->fscache.work)) { | 210 | if (work_pending(&xobject->fscache.work)) { |
211 | _debug("queue OBJ%x behind OBJ%x immediately", | 211 | _debug("queue OBJ%x behind OBJ%x immediately", |
212 | object->fscache.debug_id, | 212 | object->fscache.debug_id, |
213 | xobject->fscache.debug_id); | 213 | xobject->fscache.debug_id); |
214 | goto requeue; | 214 | goto requeue; |
215 | } | 215 | } |
216 | 216 | ||
217 | /* otherwise we sleep until either the object we're waiting for | 217 | /* otherwise we sleep until either the object we're waiting for |
218 | * is done, or the fscache_object is congested */ | 218 | * is done, or the fscache_object is congested */ |
219 | wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); | 219 | wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); |
220 | init_wait(&wait); | 220 | init_wait(&wait); |
221 | requeue = false; | 221 | requeue = false; |
222 | do { | 222 | do { |
223 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); | 223 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); |
224 | if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) | 224 | if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) |
225 | break; | 225 | break; |
226 | 226 | ||
227 | requeue = fscache_object_sleep_till_congested(&timeout); | 227 | requeue = fscache_object_sleep_till_congested(&timeout); |
228 | } while (timeout > 0 && !requeue); | 228 | } while (timeout > 0 && !requeue); |
229 | finish_wait(wq, &wait); | 229 | finish_wait(wq, &wait); |
230 | 230 | ||
231 | if (requeue && | 231 | if (requeue && |
232 | test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { | 232 | test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { |
233 | _debug("queue OBJ%x behind OBJ%x after wait", | 233 | _debug("queue OBJ%x behind OBJ%x after wait", |
234 | object->fscache.debug_id, | 234 | object->fscache.debug_id, |
235 | xobject->fscache.debug_id); | 235 | xobject->fscache.debug_id); |
236 | goto requeue; | 236 | goto requeue; |
237 | } | 237 | } |
238 | 238 | ||
239 | if (timeout <= 0) { | 239 | if (timeout <= 0) { |
240 | pr_err("\n"); | 240 | pr_err("\n"); |
241 | pr_err("Error: Overlong wait for old active object to go away\n"); | 241 | pr_err("Error: Overlong wait for old active object to go away\n"); |
242 | cachefiles_printk_object(object, xobject); | 242 | cachefiles_printk_object(object, xobject); |
243 | goto requeue; | 243 | goto requeue; |
244 | } | 244 | } |
245 | } | 245 | } |
246 | 246 | ||
247 | ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)); | 247 | ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)); |
248 | 248 | ||
249 | cache->cache.ops->put_object(&xobject->fscache); | 249 | cache->cache.ops->put_object(&xobject->fscache); |
250 | goto try_again; | 250 | goto try_again; |
251 | 251 | ||
252 | requeue: | 252 | requeue: |
253 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | 253 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); |
254 | cache->cache.ops->put_object(&xobject->fscache); | 254 | cache->cache.ops->put_object(&xobject->fscache); |
255 | _leave(" = -ETIMEDOUT"); | 255 | _leave(" = -ETIMEDOUT"); |
256 | return -ETIMEDOUT; | 256 | return -ETIMEDOUT; |
257 | } | 257 | } |
258 | 258 | ||
259 | /* | 259 | /* |
260 | * delete an object representation from the cache | 260 | * delete an object representation from the cache |
261 | * - file backed objects are unlinked | 261 | * - file backed objects are unlinked |
262 | * - directory backed objects are stuffed into the graveyard for userspace to | 262 | * - directory backed objects are stuffed into the graveyard for userspace to |
263 | * delete | 263 | * delete |
264 | * - unlocks the directory mutex | 264 | * - unlocks the directory mutex |
265 | */ | 265 | */ |
266 | static int cachefiles_bury_object(struct cachefiles_cache *cache, | 266 | static int cachefiles_bury_object(struct cachefiles_cache *cache, |
267 | struct dentry *dir, | 267 | struct dentry *dir, |
268 | struct dentry *rep, | 268 | struct dentry *rep, |
269 | bool preemptive) | 269 | bool preemptive) |
270 | { | 270 | { |
271 | struct dentry *grave, *trap; | 271 | struct dentry *grave, *trap; |
272 | struct path path, path_to_graveyard; | 272 | struct path path, path_to_graveyard; |
273 | char nbuffer[8 + 8 + 1]; | 273 | char nbuffer[8 + 8 + 1]; |
274 | int ret; | 274 | int ret; |
275 | 275 | ||
276 | _enter(",'%*.*s','%*.*s'", | 276 | _enter(",'%*.*s','%*.*s'", |
277 | dir->d_name.len, dir->d_name.len, dir->d_name.name, | 277 | dir->d_name.len, dir->d_name.len, dir->d_name.name, |
278 | rep->d_name.len, rep->d_name.len, rep->d_name.name); | 278 | rep->d_name.len, rep->d_name.len, rep->d_name.name); |
279 | 279 | ||
280 | _debug("remove %p from %p", rep, dir); | 280 | _debug("remove %p from %p", rep, dir); |
281 | 281 | ||
282 | /* non-directories can just be unlinked */ | 282 | /* non-directories can just be unlinked */ |
283 | if (!S_ISDIR(rep->d_inode->i_mode)) { | 283 | if (!S_ISDIR(rep->d_inode->i_mode)) { |
284 | _debug("unlink stale object"); | 284 | _debug("unlink stale object"); |
285 | 285 | ||
286 | path.mnt = cache->mnt; | 286 | path.mnt = cache->mnt; |
287 | path.dentry = dir; | 287 | path.dentry = dir; |
288 | ret = security_path_unlink(&path, rep); | 288 | ret = security_path_unlink(&path, rep); |
289 | if (ret < 0) { | 289 | if (ret < 0) { |
290 | cachefiles_io_error(cache, "Unlink security error"); | 290 | cachefiles_io_error(cache, "Unlink security error"); |
291 | } else { | 291 | } else { |
292 | ret = vfs_unlink(dir->d_inode, rep, NULL); | 292 | ret = vfs_unlink(dir->d_inode, rep, NULL); |
293 | 293 | ||
294 | if (preemptive) | 294 | if (preemptive) |
295 | cachefiles_mark_object_buried(cache, rep); | 295 | cachefiles_mark_object_buried(cache, rep); |
296 | } | 296 | } |
297 | 297 | ||
298 | mutex_unlock(&dir->d_inode->i_mutex); | 298 | mutex_unlock(&dir->d_inode->i_mutex); |
299 | 299 | ||
300 | if (ret == -EIO) | 300 | if (ret == -EIO) |
301 | cachefiles_io_error(cache, "Unlink failed"); | 301 | cachefiles_io_error(cache, "Unlink failed"); |
302 | 302 | ||
303 | _leave(" = %d", ret); | 303 | _leave(" = %d", ret); |
304 | return ret; | 304 | return ret; |
305 | } | 305 | } |
306 | 306 | ||
307 | /* directories have to be moved to the graveyard */ | 307 | /* directories have to be moved to the graveyard */ |
308 | _debug("move stale object to graveyard"); | 308 | _debug("move stale object to graveyard"); |
309 | mutex_unlock(&dir->d_inode->i_mutex); | 309 | mutex_unlock(&dir->d_inode->i_mutex); |
310 | 310 | ||
311 | try_again: | 311 | try_again: |
312 | /* first step is to make up a grave dentry in the graveyard */ | 312 | /* first step is to make up a grave dentry in the graveyard */ |
313 | sprintf(nbuffer, "%08x%08x", | 313 | sprintf(nbuffer, "%08x%08x", |
314 | (uint32_t) get_seconds(), | 314 | (uint32_t) get_seconds(), |
315 | (uint32_t) atomic_inc_return(&cache->gravecounter)); | 315 | (uint32_t) atomic_inc_return(&cache->gravecounter)); |
316 | 316 | ||
317 | /* do the multiway lock magic */ | 317 | /* do the multiway lock magic */ |
318 | trap = lock_rename(cache->graveyard, dir); | 318 | trap = lock_rename(cache->graveyard, dir); |
319 | 319 | ||
320 | /* do some checks before getting the grave dentry */ | 320 | /* do some checks before getting the grave dentry */ |
321 | if (rep->d_parent != dir) { | 321 | if (rep->d_parent != dir) { |
322 | /* the entry was probably culled when we dropped the parent dir | 322 | /* the entry was probably culled when we dropped the parent dir |
323 | * lock */ | 323 | * lock */ |
324 | unlock_rename(cache->graveyard, dir); | 324 | unlock_rename(cache->graveyard, dir); |
325 | _leave(" = 0 [culled?]"); | 325 | _leave(" = 0 [culled?]"); |
326 | return 0; | 326 | return 0; |
327 | } | 327 | } |
328 | 328 | ||
329 | if (!S_ISDIR(cache->graveyard->d_inode->i_mode)) { | 329 | if (!S_ISDIR(cache->graveyard->d_inode->i_mode)) { |
330 | unlock_rename(cache->graveyard, dir); | 330 | unlock_rename(cache->graveyard, dir); |
331 | cachefiles_io_error(cache, "Graveyard no longer a directory"); | 331 | cachefiles_io_error(cache, "Graveyard no longer a directory"); |
332 | return -EIO; | 332 | return -EIO; |
333 | } | 333 | } |
334 | 334 | ||
335 | if (trap == rep) { | 335 | if (trap == rep) { |
336 | unlock_rename(cache->graveyard, dir); | 336 | unlock_rename(cache->graveyard, dir); |
337 | cachefiles_io_error(cache, "May not make directory loop"); | 337 | cachefiles_io_error(cache, "May not make directory loop"); |
338 | return -EIO; | 338 | return -EIO; |
339 | } | 339 | } |
340 | 340 | ||
341 | if (d_mountpoint(rep)) { | 341 | if (d_mountpoint(rep)) { |
342 | unlock_rename(cache->graveyard, dir); | 342 | unlock_rename(cache->graveyard, dir); |
343 | cachefiles_io_error(cache, "Mountpoint in cache"); | 343 | cachefiles_io_error(cache, "Mountpoint in cache"); |
344 | return -EIO; | 344 | return -EIO; |
345 | } | 345 | } |
346 | 346 | ||
347 | grave = lookup_one_len(nbuffer, cache->graveyard, strlen(nbuffer)); | 347 | grave = lookup_one_len(nbuffer, cache->graveyard, strlen(nbuffer)); |
348 | if (IS_ERR(grave)) { | 348 | if (IS_ERR(grave)) { |
349 | unlock_rename(cache->graveyard, dir); | 349 | unlock_rename(cache->graveyard, dir); |
350 | 350 | ||
351 | if (PTR_ERR(grave) == -ENOMEM) { | 351 | if (PTR_ERR(grave) == -ENOMEM) { |
352 | _leave(" = -ENOMEM"); | 352 | _leave(" = -ENOMEM"); |
353 | return -ENOMEM; | 353 | return -ENOMEM; |
354 | } | 354 | } |
355 | 355 | ||
356 | cachefiles_io_error(cache, "Lookup error %ld", | 356 | cachefiles_io_error(cache, "Lookup error %ld", |
357 | PTR_ERR(grave)); | 357 | PTR_ERR(grave)); |
358 | return -EIO; | 358 | return -EIO; |
359 | } | 359 | } |
360 | 360 | ||
361 | if (grave->d_inode) { | 361 | if (grave->d_inode) { |
362 | unlock_rename(cache->graveyard, dir); | 362 | unlock_rename(cache->graveyard, dir); |
363 | dput(grave); | 363 | dput(grave); |
364 | grave = NULL; | 364 | grave = NULL; |
365 | cond_resched(); | 365 | cond_resched(); |
366 | goto try_again; | 366 | goto try_again; |
367 | } | 367 | } |
368 | 368 | ||
369 | if (d_mountpoint(grave)) { | 369 | if (d_mountpoint(grave)) { |
370 | unlock_rename(cache->graveyard, dir); | 370 | unlock_rename(cache->graveyard, dir); |
371 | dput(grave); | 371 | dput(grave); |
372 | cachefiles_io_error(cache, "Mountpoint in graveyard"); | 372 | cachefiles_io_error(cache, "Mountpoint in graveyard"); |
373 | return -EIO; | 373 | return -EIO; |
374 | } | 374 | } |
375 | 375 | ||
376 | /* target should not be an ancestor of source */ | 376 | /* target should not be an ancestor of source */ |
377 | if (trap == grave) { | 377 | if (trap == grave) { |
378 | unlock_rename(cache->graveyard, dir); | 378 | unlock_rename(cache->graveyard, dir); |
379 | dput(grave); | 379 | dput(grave); |
380 | cachefiles_io_error(cache, "May not make directory loop"); | 380 | cachefiles_io_error(cache, "May not make directory loop"); |
381 | return -EIO; | 381 | return -EIO; |
382 | } | 382 | } |
383 | 383 | ||
384 | /* attempt the rename */ | 384 | /* attempt the rename */ |
385 | path.mnt = cache->mnt; | 385 | path.mnt = cache->mnt; |
386 | path.dentry = dir; | 386 | path.dentry = dir; |
387 | path_to_graveyard.mnt = cache->mnt; | 387 | path_to_graveyard.mnt = cache->mnt; |
388 | path_to_graveyard.dentry = cache->graveyard; | 388 | path_to_graveyard.dentry = cache->graveyard; |
389 | ret = security_path_rename(&path, rep, &path_to_graveyard, grave, 0); | 389 | ret = security_path_rename(&path, rep, &path_to_graveyard, grave, 0); |
390 | if (ret < 0) { | 390 | if (ret < 0) { |
391 | cachefiles_io_error(cache, "Rename security error %d", ret); | 391 | cachefiles_io_error(cache, "Rename security error %d", ret); |
392 | } else { | 392 | } else { |
393 | ret = vfs_rename(dir->d_inode, rep, | 393 | ret = vfs_rename(dir->d_inode, rep, |
394 | cache->graveyard->d_inode, grave, NULL, 0); | 394 | cache->graveyard->d_inode, grave, NULL, 0); |
395 | if (ret != 0 && ret != -ENOMEM) | 395 | if (ret != 0 && ret != -ENOMEM) |
396 | cachefiles_io_error(cache, | 396 | cachefiles_io_error(cache, |
397 | "Rename failed with error %d", ret); | 397 | "Rename failed with error %d", ret); |
398 | 398 | ||
399 | if (preemptive) | 399 | if (preemptive) |
400 | cachefiles_mark_object_buried(cache, rep); | 400 | cachefiles_mark_object_buried(cache, rep); |
401 | } | 401 | } |
402 | 402 | ||
403 | unlock_rename(cache->graveyard, dir); | 403 | unlock_rename(cache->graveyard, dir); |
404 | dput(grave); | 404 | dput(grave); |
405 | _leave(" = 0"); | 405 | _leave(" = 0"); |
406 | return 0; | 406 | return 0; |
407 | } | 407 | } |
408 | 408 | ||
409 | /* | 409 | /* |
410 | * delete an object representation from the cache | 410 | * delete an object representation from the cache |
411 | */ | 411 | */ |
412 | int cachefiles_delete_object(struct cachefiles_cache *cache, | 412 | int cachefiles_delete_object(struct cachefiles_cache *cache, |
413 | struct cachefiles_object *object) | 413 | struct cachefiles_object *object) |
414 | { | 414 | { |
415 | struct dentry *dir; | 415 | struct dentry *dir; |
416 | int ret; | 416 | int ret; |
417 | 417 | ||
418 | _enter(",OBJ%x{%p}", object->fscache.debug_id, object->dentry); | 418 | _enter(",OBJ%x{%p}", object->fscache.debug_id, object->dentry); |
419 | 419 | ||
420 | ASSERT(object->dentry); | 420 | ASSERT(object->dentry); |
421 | ASSERT(object->dentry->d_inode); | 421 | ASSERT(object->dentry->d_inode); |
422 | ASSERT(object->dentry->d_parent); | 422 | ASSERT(object->dentry->d_parent); |
423 | 423 | ||
424 | dir = dget_parent(object->dentry); | 424 | dir = dget_parent(object->dentry); |
425 | 425 | ||
426 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 426 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
427 | 427 | ||
428 | if (test_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { | 428 | if (test_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { |
429 | /* object allocation for the same key preemptively deleted this | 429 | /* object allocation for the same key preemptively deleted this |
430 | * object's file so that it could create its own file */ | 430 | * object's file so that it could create its own file */ |
431 | _debug("object preemptively buried"); | 431 | _debug("object preemptively buried"); |
432 | mutex_unlock(&dir->d_inode->i_mutex); | 432 | mutex_unlock(&dir->d_inode->i_mutex); |
433 | ret = 0; | 433 | ret = 0; |
434 | } else { | 434 | } else { |
435 | /* we need to check that our parent is _still_ our parent - it | 435 | /* we need to check that our parent is _still_ our parent - it |
436 | * may have been renamed */ | 436 | * may have been renamed */ |
437 | if (dir == object->dentry->d_parent) { | 437 | if (dir == object->dentry->d_parent) { |
438 | ret = cachefiles_bury_object(cache, dir, | 438 | ret = cachefiles_bury_object(cache, dir, |
439 | object->dentry, false); | 439 | object->dentry, false); |
440 | } else { | 440 | } else { |
441 | /* it got moved, presumably by cachefilesd culling it, | 441 | /* it got moved, presumably by cachefilesd culling it, |
442 | * so it's no longer in the key path and we can ignore | 442 | * so it's no longer in the key path and we can ignore |
443 | * it */ | 443 | * it */ |
444 | mutex_unlock(&dir->d_inode->i_mutex); | 444 | mutex_unlock(&dir->d_inode->i_mutex); |
445 | ret = 0; | 445 | ret = 0; |
446 | } | 446 | } |
447 | } | 447 | } |
448 | 448 | ||
449 | dput(dir); | 449 | dput(dir); |
450 | _leave(" = %d", ret); | 450 | _leave(" = %d", ret); |
451 | return ret; | 451 | return ret; |
452 | } | 452 | } |
453 | 453 | ||
454 | /* | 454 | /* |
455 | * walk from the parent object to the child object through the backing | 455 | * walk from the parent object to the child object through the backing |
456 | * filesystem, creating directories as we go | 456 | * filesystem, creating directories as we go |
457 | */ | 457 | */ |
458 | int cachefiles_walk_to_object(struct cachefiles_object *parent, | 458 | int cachefiles_walk_to_object(struct cachefiles_object *parent, |
459 | struct cachefiles_object *object, | 459 | struct cachefiles_object *object, |
460 | const char *key, | 460 | const char *key, |
461 | struct cachefiles_xattr *auxdata) | 461 | struct cachefiles_xattr *auxdata) |
462 | { | 462 | { |
463 | struct cachefiles_cache *cache; | 463 | struct cachefiles_cache *cache; |
464 | struct dentry *dir, *next = NULL; | 464 | struct dentry *dir, *next = NULL; |
465 | struct path path; | 465 | struct path path; |
466 | unsigned long start; | 466 | unsigned long start; |
467 | const char *name; | 467 | const char *name; |
468 | int ret, nlen; | 468 | int ret, nlen; |
469 | 469 | ||
470 | _enter("OBJ%x{%p},OBJ%x,%s,", | 470 | _enter("OBJ%x{%p},OBJ%x,%s,", |
471 | parent->fscache.debug_id, parent->dentry, | 471 | parent->fscache.debug_id, parent->dentry, |
472 | object->fscache.debug_id, key); | 472 | object->fscache.debug_id, key); |
473 | 473 | ||
474 | cache = container_of(parent->fscache.cache, | 474 | cache = container_of(parent->fscache.cache, |
475 | struct cachefiles_cache, cache); | 475 | struct cachefiles_cache, cache); |
476 | path.mnt = cache->mnt; | 476 | path.mnt = cache->mnt; |
477 | 477 | ||
478 | ASSERT(parent->dentry); | 478 | ASSERT(parent->dentry); |
479 | ASSERT(parent->dentry->d_inode); | 479 | ASSERT(parent->dentry->d_inode); |
480 | 480 | ||
481 | if (!(S_ISDIR(parent->dentry->d_inode->i_mode))) { | 481 | if (!(S_ISDIR(parent->dentry->d_inode->i_mode))) { |
482 | // TODO: convert file to dir | 482 | // TODO: convert file to dir |
483 | _leave("looking up in none directory"); | 483 | _leave("looking up in none directory"); |
484 | return -ENOBUFS; | 484 | return -ENOBUFS; |
485 | } | 485 | } |
486 | 486 | ||
487 | dir = dget(parent->dentry); | 487 | dir = dget(parent->dentry); |
488 | 488 | ||
489 | advance: | 489 | advance: |
490 | /* attempt to transit the first directory component */ | 490 | /* attempt to transit the first directory component */ |
491 | name = key; | 491 | name = key; |
492 | nlen = strlen(key); | 492 | nlen = strlen(key); |
493 | 493 | ||
494 | /* key ends in a double NUL */ | 494 | /* key ends in a double NUL */ |
495 | key = key + nlen + 1; | 495 | key = key + nlen + 1; |
496 | if (!*key) | 496 | if (!*key) |
497 | key = NULL; | 497 | key = NULL; |
498 | 498 | ||
499 | lookup_again: | 499 | lookup_again: |
500 | /* search the current directory for the element name */ | 500 | /* search the current directory for the element name */ |
501 | _debug("lookup '%s'", name); | 501 | _debug("lookup '%s'", name); |
502 | 502 | ||
503 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 503 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
504 | 504 | ||
505 | start = jiffies; | 505 | start = jiffies; |
506 | next = lookup_one_len(name, dir, nlen); | 506 | next = lookup_one_len(name, dir, nlen); |
507 | cachefiles_hist(cachefiles_lookup_histogram, start); | 507 | cachefiles_hist(cachefiles_lookup_histogram, start); |
508 | if (IS_ERR(next)) | 508 | if (IS_ERR(next)) |
509 | goto lookup_error; | 509 | goto lookup_error; |
510 | 510 | ||
511 | _debug("next -> %p %s", next, next->d_inode ? "positive" : "negative"); | 511 | _debug("next -> %p %s", next, next->d_inode ? "positive" : "negative"); |
512 | 512 | ||
513 | if (!key) | 513 | if (!key) |
514 | object->new = !next->d_inode; | 514 | object->new = !next->d_inode; |
515 | 515 | ||
516 | /* if this element of the path doesn't exist, then the lookup phase | 516 | /* if this element of the path doesn't exist, then the lookup phase |
517 | * failed, and we can release any readers in the certain knowledge that | 517 | * failed, and we can release any readers in the certain knowledge that |
518 | * there's nothing for them to actually read */ | 518 | * there's nothing for them to actually read */ |
519 | if (!next->d_inode) | 519 | if (!next->d_inode) |
520 | fscache_object_lookup_negative(&object->fscache); | 520 | fscache_object_lookup_negative(&object->fscache); |
521 | 521 | ||
522 | /* we need to create the object if it's negative */ | 522 | /* we need to create the object if it's negative */ |
523 | if (key || object->type == FSCACHE_COOKIE_TYPE_INDEX) { | 523 | if (key || object->type == FSCACHE_COOKIE_TYPE_INDEX) { |
524 | /* index objects and intervening tree levels must be subdirs */ | 524 | /* index objects and intervening tree levels must be subdirs */ |
525 | if (!next->d_inode) { | 525 | if (!next->d_inode) { |
526 | ret = cachefiles_has_space(cache, 1, 0); | 526 | ret = cachefiles_has_space(cache, 1, 0); |
527 | if (ret < 0) | 527 | if (ret < 0) |
528 | goto create_error; | 528 | goto create_error; |
529 | 529 | ||
530 | path.dentry = dir; | 530 | path.dentry = dir; |
531 | ret = security_path_mkdir(&path, next, 0); | 531 | ret = security_path_mkdir(&path, next, 0); |
532 | if (ret < 0) | 532 | if (ret < 0) |
533 | goto create_error; | 533 | goto create_error; |
534 | start = jiffies; | 534 | start = jiffies; |
535 | ret = vfs_mkdir(dir->d_inode, next, 0); | 535 | ret = vfs_mkdir(dir->d_inode, next, 0); |
536 | cachefiles_hist(cachefiles_mkdir_histogram, start); | 536 | cachefiles_hist(cachefiles_mkdir_histogram, start); |
537 | if (ret < 0) | 537 | if (ret < 0) |
538 | goto create_error; | 538 | goto create_error; |
539 | 539 | ||
540 | ASSERT(next->d_inode); | 540 | ASSERT(next->d_inode); |
541 | 541 | ||
542 | _debug("mkdir -> %p{%p{ino=%lu}}", | 542 | _debug("mkdir -> %p{%p{ino=%lu}}", |
543 | next, next->d_inode, next->d_inode->i_ino); | 543 | next, next->d_inode, next->d_inode->i_ino); |
544 | 544 | ||
545 | } else if (!S_ISDIR(next->d_inode->i_mode)) { | 545 | } else if (!S_ISDIR(next->d_inode->i_mode)) { |
546 | pr_err("inode %lu is not a directory", | 546 | pr_err("inode %lu is not a directory\n", |
547 | next->d_inode->i_ino); | 547 | next->d_inode->i_ino); |
548 | ret = -ENOBUFS; | 548 | ret = -ENOBUFS; |
549 | goto error; | 549 | goto error; |
550 | } | 550 | } |
551 | 551 | ||
552 | } else { | 552 | } else { |
553 | /* non-index objects start out life as files */ | 553 | /* non-index objects start out life as files */ |
554 | if (!next->d_inode) { | 554 | if (!next->d_inode) { |
555 | ret = cachefiles_has_space(cache, 1, 0); | 555 | ret = cachefiles_has_space(cache, 1, 0); |
556 | if (ret < 0) | 556 | if (ret < 0) |
557 | goto create_error; | 557 | goto create_error; |
558 | 558 | ||
559 | path.dentry = dir; | 559 | path.dentry = dir; |
560 | ret = security_path_mknod(&path, next, S_IFREG, 0); | 560 | ret = security_path_mknod(&path, next, S_IFREG, 0); |
561 | if (ret < 0) | 561 | if (ret < 0) |
562 | goto create_error; | 562 | goto create_error; |
563 | start = jiffies; | 563 | start = jiffies; |
564 | ret = vfs_create(dir->d_inode, next, S_IFREG, true); | 564 | ret = vfs_create(dir->d_inode, next, S_IFREG, true); |
565 | cachefiles_hist(cachefiles_create_histogram, start); | 565 | cachefiles_hist(cachefiles_create_histogram, start); |
566 | if (ret < 0) | 566 | if (ret < 0) |
567 | goto create_error; | 567 | goto create_error; |
568 | 568 | ||
569 | ASSERT(next->d_inode); | 569 | ASSERT(next->d_inode); |
570 | 570 | ||
571 | _debug("create -> %p{%p{ino=%lu}}", | 571 | _debug("create -> %p{%p{ino=%lu}}", |
572 | next, next->d_inode, next->d_inode->i_ino); | 572 | next, next->d_inode, next->d_inode->i_ino); |
573 | 573 | ||
574 | } else if (!S_ISDIR(next->d_inode->i_mode) && | 574 | } else if (!S_ISDIR(next->d_inode->i_mode) && |
575 | !S_ISREG(next->d_inode->i_mode) | 575 | !S_ISREG(next->d_inode->i_mode) |
576 | ) { | 576 | ) { |
577 | pr_err("inode %lu is not a file or directory", | 577 | pr_err("inode %lu is not a file or directory\n", |
578 | next->d_inode->i_ino); | 578 | next->d_inode->i_ino); |
579 | ret = -ENOBUFS; | 579 | ret = -ENOBUFS; |
580 | goto error; | 580 | goto error; |
581 | } | 581 | } |
582 | } | 582 | } |
583 | 583 | ||
584 | /* process the next component */ | 584 | /* process the next component */ |
585 | if (key) { | 585 | if (key) { |
586 | _debug("advance"); | 586 | _debug("advance"); |
587 | mutex_unlock(&dir->d_inode->i_mutex); | 587 | mutex_unlock(&dir->d_inode->i_mutex); |
588 | dput(dir); | 588 | dput(dir); |
589 | dir = next; | 589 | dir = next; |
590 | next = NULL; | 590 | next = NULL; |
591 | goto advance; | 591 | goto advance; |
592 | } | 592 | } |
593 | 593 | ||
594 | /* we've found the object we were looking for */ | 594 | /* we've found the object we were looking for */ |
595 | object->dentry = next; | 595 | object->dentry = next; |
596 | 596 | ||
597 | /* if we've found that the terminal object exists, then we need to | 597 | /* if we've found that the terminal object exists, then we need to |
598 | * check its attributes and delete it if it's out of date */ | 598 | * check its attributes and delete it if it's out of date */ |
599 | if (!object->new) { | 599 | if (!object->new) { |
600 | _debug("validate '%*.*s'", | 600 | _debug("validate '%*.*s'", |
601 | next->d_name.len, next->d_name.len, next->d_name.name); | 601 | next->d_name.len, next->d_name.len, next->d_name.name); |
602 | 602 | ||
603 | ret = cachefiles_check_object_xattr(object, auxdata); | 603 | ret = cachefiles_check_object_xattr(object, auxdata); |
604 | if (ret == -ESTALE) { | 604 | if (ret == -ESTALE) { |
605 | /* delete the object (the deleter drops the directory | 605 | /* delete the object (the deleter drops the directory |
606 | * mutex) */ | 606 | * mutex) */ |
607 | object->dentry = NULL; | 607 | object->dentry = NULL; |
608 | 608 | ||
609 | ret = cachefiles_bury_object(cache, dir, next, true); | 609 | ret = cachefiles_bury_object(cache, dir, next, true); |
610 | dput(next); | 610 | dput(next); |
611 | next = NULL; | 611 | next = NULL; |
612 | 612 | ||
613 | if (ret < 0) | 613 | if (ret < 0) |
614 | goto delete_error; | 614 | goto delete_error; |
615 | 615 | ||
616 | _debug("redo lookup"); | 616 | _debug("redo lookup"); |
617 | goto lookup_again; | 617 | goto lookup_again; |
618 | } | 618 | } |
619 | } | 619 | } |
620 | 620 | ||
621 | /* note that we're now using this object */ | 621 | /* note that we're now using this object */ |
622 | ret = cachefiles_mark_object_active(cache, object); | 622 | ret = cachefiles_mark_object_active(cache, object); |
623 | 623 | ||
624 | mutex_unlock(&dir->d_inode->i_mutex); | 624 | mutex_unlock(&dir->d_inode->i_mutex); |
625 | dput(dir); | 625 | dput(dir); |
626 | dir = NULL; | 626 | dir = NULL; |
627 | 627 | ||
628 | if (ret == -ETIMEDOUT) | 628 | if (ret == -ETIMEDOUT) |
629 | goto mark_active_timed_out; | 629 | goto mark_active_timed_out; |
630 | 630 | ||
631 | _debug("=== OBTAINED_OBJECT ==="); | 631 | _debug("=== OBTAINED_OBJECT ==="); |
632 | 632 | ||
633 | if (object->new) { | 633 | if (object->new) { |
634 | /* attach data to a newly constructed terminal object */ | 634 | /* attach data to a newly constructed terminal object */ |
635 | ret = cachefiles_set_object_xattr(object, auxdata); | 635 | ret = cachefiles_set_object_xattr(object, auxdata); |
636 | if (ret < 0) | 636 | if (ret < 0) |
637 | goto check_error; | 637 | goto check_error; |
638 | } else { | 638 | } else { |
639 | /* always update the atime on an object we've just looked up | 639 | /* always update the atime on an object we've just looked up |
640 | * (this is used to keep track of culling, and atimes are only | 640 | * (this is used to keep track of culling, and atimes are only |
641 | * updated by read, write and readdir but not lookup or | 641 | * updated by read, write and readdir but not lookup or |
642 | * open) */ | 642 | * open) */ |
643 | path.dentry = next; | 643 | path.dentry = next; |
644 | touch_atime(&path); | 644 | touch_atime(&path); |
645 | } | 645 | } |
646 | 646 | ||
647 | /* open a file interface onto a data file */ | 647 | /* open a file interface onto a data file */ |
648 | if (object->type != FSCACHE_COOKIE_TYPE_INDEX) { | 648 | if (object->type != FSCACHE_COOKIE_TYPE_INDEX) { |
649 | if (S_ISREG(object->dentry->d_inode->i_mode)) { | 649 | if (S_ISREG(object->dentry->d_inode->i_mode)) { |
650 | const struct address_space_operations *aops; | 650 | const struct address_space_operations *aops; |
651 | 651 | ||
652 | ret = -EPERM; | 652 | ret = -EPERM; |
653 | aops = object->dentry->d_inode->i_mapping->a_ops; | 653 | aops = object->dentry->d_inode->i_mapping->a_ops; |
654 | if (!aops->bmap) | 654 | if (!aops->bmap) |
655 | goto check_error; | 655 | goto check_error; |
656 | 656 | ||
657 | object->backer = object->dentry; | 657 | object->backer = object->dentry; |
658 | } else { | 658 | } else { |
659 | BUG(); // TODO: open file in data-class subdir | 659 | BUG(); // TODO: open file in data-class subdir |
660 | } | 660 | } |
661 | } | 661 | } |
662 | 662 | ||
663 | object->new = 0; | 663 | object->new = 0; |
664 | fscache_obtained_object(&object->fscache); | 664 | fscache_obtained_object(&object->fscache); |
665 | 665 | ||
666 | _leave(" = 0 [%lu]", object->dentry->d_inode->i_ino); | 666 | _leave(" = 0 [%lu]", object->dentry->d_inode->i_ino); |
667 | return 0; | 667 | return 0; |
668 | 668 | ||
669 | create_error: | 669 | create_error: |
670 | _debug("create error %d", ret); | 670 | _debug("create error %d", ret); |
671 | if (ret == -EIO) | 671 | if (ret == -EIO) |
672 | cachefiles_io_error(cache, "Create/mkdir failed"); | 672 | cachefiles_io_error(cache, "Create/mkdir failed"); |
673 | goto error; | 673 | goto error; |
674 | 674 | ||
675 | mark_active_timed_out: | 675 | mark_active_timed_out: |
676 | _debug("mark active timed out"); | 676 | _debug("mark active timed out"); |
677 | goto release_dentry; | 677 | goto release_dentry; |
678 | 678 | ||
679 | check_error: | 679 | check_error: |
680 | _debug("check error %d", ret); | 680 | _debug("check error %d", ret); |
681 | write_lock(&cache->active_lock); | 681 | write_lock(&cache->active_lock); |
682 | rb_erase(&object->active_node, &cache->active_nodes); | 682 | rb_erase(&object->active_node, &cache->active_nodes); |
683 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | 683 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); |
684 | wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); | 684 | wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); |
685 | write_unlock(&cache->active_lock); | 685 | write_unlock(&cache->active_lock); |
686 | release_dentry: | 686 | release_dentry: |
687 | dput(object->dentry); | 687 | dput(object->dentry); |
688 | object->dentry = NULL; | 688 | object->dentry = NULL; |
689 | goto error_out; | 689 | goto error_out; |
690 | 690 | ||
691 | delete_error: | 691 | delete_error: |
692 | _debug("delete error %d", ret); | 692 | _debug("delete error %d", ret); |
693 | goto error_out2; | 693 | goto error_out2; |
694 | 694 | ||
695 | lookup_error: | 695 | lookup_error: |
696 | _debug("lookup error %ld", PTR_ERR(next)); | 696 | _debug("lookup error %ld", PTR_ERR(next)); |
697 | ret = PTR_ERR(next); | 697 | ret = PTR_ERR(next); |
698 | if (ret == -EIO) | 698 | if (ret == -EIO) |
699 | cachefiles_io_error(cache, "Lookup failed"); | 699 | cachefiles_io_error(cache, "Lookup failed"); |
700 | next = NULL; | 700 | next = NULL; |
701 | error: | 701 | error: |
702 | mutex_unlock(&dir->d_inode->i_mutex); | 702 | mutex_unlock(&dir->d_inode->i_mutex); |
703 | dput(next); | 703 | dput(next); |
704 | error_out2: | 704 | error_out2: |
705 | dput(dir); | 705 | dput(dir); |
706 | error_out: | 706 | error_out: |
707 | _leave(" = error %d", -ret); | 707 | _leave(" = error %d", -ret); |
708 | return ret; | 708 | return ret; |
709 | } | 709 | } |
710 | 710 | ||
711 | /* | 711 | /* |
712 | * get a subdirectory | 712 | * get a subdirectory |
713 | */ | 713 | */ |
714 | struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, | 714 | struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, |
715 | struct dentry *dir, | 715 | struct dentry *dir, |
716 | const char *dirname) | 716 | const char *dirname) |
717 | { | 717 | { |
718 | struct dentry *subdir; | 718 | struct dentry *subdir; |
719 | unsigned long start; | 719 | unsigned long start; |
720 | struct path path; | 720 | struct path path; |
721 | int ret; | 721 | int ret; |
722 | 722 | ||
723 | _enter(",,%s", dirname); | 723 | _enter(",,%s", dirname); |
724 | 724 | ||
725 | /* search the current directory for the element name */ | 725 | /* search the current directory for the element name */ |
726 | mutex_lock(&dir->d_inode->i_mutex); | 726 | mutex_lock(&dir->d_inode->i_mutex); |
727 | 727 | ||
728 | start = jiffies; | 728 | start = jiffies; |
729 | subdir = lookup_one_len(dirname, dir, strlen(dirname)); | 729 | subdir = lookup_one_len(dirname, dir, strlen(dirname)); |
730 | cachefiles_hist(cachefiles_lookup_histogram, start); | 730 | cachefiles_hist(cachefiles_lookup_histogram, start); |
731 | if (IS_ERR(subdir)) { | 731 | if (IS_ERR(subdir)) { |
732 | if (PTR_ERR(subdir) == -ENOMEM) | 732 | if (PTR_ERR(subdir) == -ENOMEM) |
733 | goto nomem_d_alloc; | 733 | goto nomem_d_alloc; |
734 | goto lookup_error; | 734 | goto lookup_error; |
735 | } | 735 | } |
736 | 736 | ||
737 | _debug("subdir -> %p %s", | 737 | _debug("subdir -> %p %s", |
738 | subdir, subdir->d_inode ? "positive" : "negative"); | 738 | subdir, subdir->d_inode ? "positive" : "negative"); |
739 | 739 | ||
740 | /* we need to create the subdir if it doesn't exist yet */ | 740 | /* we need to create the subdir if it doesn't exist yet */ |
741 | if (!subdir->d_inode) { | 741 | if (!subdir->d_inode) { |
742 | ret = cachefiles_has_space(cache, 1, 0); | 742 | ret = cachefiles_has_space(cache, 1, 0); |
743 | if (ret < 0) | 743 | if (ret < 0) |
744 | goto mkdir_error; | 744 | goto mkdir_error; |
745 | 745 | ||
746 | _debug("attempt mkdir"); | 746 | _debug("attempt mkdir"); |
747 | 747 | ||
748 | path.mnt = cache->mnt; | 748 | path.mnt = cache->mnt; |
749 | path.dentry = dir; | 749 | path.dentry = dir; |
750 | ret = security_path_mkdir(&path, subdir, 0700); | 750 | ret = security_path_mkdir(&path, subdir, 0700); |
751 | if (ret < 0) | 751 | if (ret < 0) |
752 | goto mkdir_error; | 752 | goto mkdir_error; |
753 | ret = vfs_mkdir(dir->d_inode, subdir, 0700); | 753 | ret = vfs_mkdir(dir->d_inode, subdir, 0700); |
754 | if (ret < 0) | 754 | if (ret < 0) |
755 | goto mkdir_error; | 755 | goto mkdir_error; |
756 | 756 | ||
757 | ASSERT(subdir->d_inode); | 757 | ASSERT(subdir->d_inode); |
758 | 758 | ||
759 | _debug("mkdir -> %p{%p{ino=%lu}}", | 759 | _debug("mkdir -> %p{%p{ino=%lu}}", |
760 | subdir, | 760 | subdir, |
761 | subdir->d_inode, | 761 | subdir->d_inode, |
762 | subdir->d_inode->i_ino); | 762 | subdir->d_inode->i_ino); |
763 | } | 763 | } |
764 | 764 | ||
765 | mutex_unlock(&dir->d_inode->i_mutex); | 765 | mutex_unlock(&dir->d_inode->i_mutex); |
766 | 766 | ||
767 | /* we need to make sure the subdir is a directory */ | 767 | /* we need to make sure the subdir is a directory */ |
768 | ASSERT(subdir->d_inode); | 768 | ASSERT(subdir->d_inode); |
769 | 769 | ||
770 | if (!S_ISDIR(subdir->d_inode->i_mode)) { | 770 | if (!S_ISDIR(subdir->d_inode->i_mode)) { |
771 | pr_err("%s is not a directory", dirname); | 771 | pr_err("%s is not a directory\n", dirname); |
772 | ret = -EIO; | 772 | ret = -EIO; |
773 | goto check_error; | 773 | goto check_error; |
774 | } | 774 | } |
775 | 775 | ||
776 | ret = -EPERM; | 776 | ret = -EPERM; |
777 | if (!subdir->d_inode->i_op->setxattr || | 777 | if (!subdir->d_inode->i_op->setxattr || |
778 | !subdir->d_inode->i_op->getxattr || | 778 | !subdir->d_inode->i_op->getxattr || |
779 | !subdir->d_inode->i_op->lookup || | 779 | !subdir->d_inode->i_op->lookup || |
780 | !subdir->d_inode->i_op->mkdir || | 780 | !subdir->d_inode->i_op->mkdir || |
781 | !subdir->d_inode->i_op->create || | 781 | !subdir->d_inode->i_op->create || |
782 | (!subdir->d_inode->i_op->rename && | 782 | (!subdir->d_inode->i_op->rename && |
783 | !subdir->d_inode->i_op->rename2) || | 783 | !subdir->d_inode->i_op->rename2) || |
784 | !subdir->d_inode->i_op->rmdir || | 784 | !subdir->d_inode->i_op->rmdir || |
785 | !subdir->d_inode->i_op->unlink) | 785 | !subdir->d_inode->i_op->unlink) |
786 | goto check_error; | 786 | goto check_error; |
787 | 787 | ||
788 | _leave(" = [%lu]", subdir->d_inode->i_ino); | 788 | _leave(" = [%lu]", subdir->d_inode->i_ino); |
789 | return subdir; | 789 | return subdir; |
790 | 790 | ||
791 | check_error: | 791 | check_error: |
792 | dput(subdir); | 792 | dput(subdir); |
793 | _leave(" = %d [check]", ret); | 793 | _leave(" = %d [check]", ret); |
794 | return ERR_PTR(ret); | 794 | return ERR_PTR(ret); |
795 | 795 | ||
796 | mkdir_error: | 796 | mkdir_error: |
797 | mutex_unlock(&dir->d_inode->i_mutex); | 797 | mutex_unlock(&dir->d_inode->i_mutex); |
798 | dput(subdir); | 798 | dput(subdir); |
799 | pr_err("mkdir %s failed with error %d", dirname, ret); | 799 | pr_err("mkdir %s failed with error %d\n", dirname, ret); |
800 | return ERR_PTR(ret); | 800 | return ERR_PTR(ret); |
801 | 801 | ||
802 | lookup_error: | 802 | lookup_error: |
803 | mutex_unlock(&dir->d_inode->i_mutex); | 803 | mutex_unlock(&dir->d_inode->i_mutex); |
804 | ret = PTR_ERR(subdir); | 804 | ret = PTR_ERR(subdir); |
805 | pr_err("Lookup %s failed with error %d", dirname, ret); | 805 | pr_err("Lookup %s failed with error %d\n", dirname, ret); |
806 | return ERR_PTR(ret); | 806 | return ERR_PTR(ret); |
807 | 807 | ||
808 | nomem_d_alloc: | 808 | nomem_d_alloc: |
809 | mutex_unlock(&dir->d_inode->i_mutex); | 809 | mutex_unlock(&dir->d_inode->i_mutex); |
810 | _leave(" = -ENOMEM"); | 810 | _leave(" = -ENOMEM"); |
811 | return ERR_PTR(-ENOMEM); | 811 | return ERR_PTR(-ENOMEM); |
812 | } | 812 | } |
813 | 813 | ||
814 | /* | 814 | /* |
815 | * find out if an object is in use or not | 815 | * find out if an object is in use or not |
816 | * - if finds object and it's not in use: | 816 | * - if finds object and it's not in use: |
817 | * - returns a pointer to the object and a reference on it | 817 | * - returns a pointer to the object and a reference on it |
818 | * - returns with the directory locked | 818 | * - returns with the directory locked |
819 | */ | 819 | */ |
820 | static struct dentry *cachefiles_check_active(struct cachefiles_cache *cache, | 820 | static struct dentry *cachefiles_check_active(struct cachefiles_cache *cache, |
821 | struct dentry *dir, | 821 | struct dentry *dir, |
822 | char *filename) | 822 | char *filename) |
823 | { | 823 | { |
824 | struct cachefiles_object *object; | 824 | struct cachefiles_object *object; |
825 | struct rb_node *_n; | 825 | struct rb_node *_n; |
826 | struct dentry *victim; | 826 | struct dentry *victim; |
827 | unsigned long start; | 827 | unsigned long start; |
828 | int ret; | 828 | int ret; |
829 | 829 | ||
830 | //_enter(",%*.*s/,%s", | 830 | //_enter(",%*.*s/,%s", |
831 | // dir->d_name.len, dir->d_name.len, dir->d_name.name, filename); | 831 | // dir->d_name.len, dir->d_name.len, dir->d_name.name, filename); |
832 | 832 | ||
833 | /* look up the victim */ | 833 | /* look up the victim */ |
834 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 834 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
835 | 835 | ||
836 | start = jiffies; | 836 | start = jiffies; |
837 | victim = lookup_one_len(filename, dir, strlen(filename)); | 837 | victim = lookup_one_len(filename, dir, strlen(filename)); |
838 | cachefiles_hist(cachefiles_lookup_histogram, start); | 838 | cachefiles_hist(cachefiles_lookup_histogram, start); |
839 | if (IS_ERR(victim)) | 839 | if (IS_ERR(victim)) |
840 | goto lookup_error; | 840 | goto lookup_error; |
841 | 841 | ||
842 | //_debug("victim -> %p %s", | 842 | //_debug("victim -> %p %s", |
843 | // victim, victim->d_inode ? "positive" : "negative"); | 843 | // victim, victim->d_inode ? "positive" : "negative"); |
844 | 844 | ||
845 | /* if the object is no longer there then we probably retired the object | 845 | /* if the object is no longer there then we probably retired the object |
846 | * at the netfs's request whilst the cull was in progress | 846 | * at the netfs's request whilst the cull was in progress |
847 | */ | 847 | */ |
848 | if (!victim->d_inode) { | 848 | if (!victim->d_inode) { |
849 | mutex_unlock(&dir->d_inode->i_mutex); | 849 | mutex_unlock(&dir->d_inode->i_mutex); |
850 | dput(victim); | 850 | dput(victim); |
851 | _leave(" = -ENOENT [absent]"); | 851 | _leave(" = -ENOENT [absent]"); |
852 | return ERR_PTR(-ENOENT); | 852 | return ERR_PTR(-ENOENT); |
853 | } | 853 | } |
854 | 854 | ||
855 | /* check to see if we're using this object */ | 855 | /* check to see if we're using this object */ |
856 | read_lock(&cache->active_lock); | 856 | read_lock(&cache->active_lock); |
857 | 857 | ||
858 | _n = cache->active_nodes.rb_node; | 858 | _n = cache->active_nodes.rb_node; |
859 | 859 | ||
860 | while (_n) { | 860 | while (_n) { |
861 | object = rb_entry(_n, struct cachefiles_object, active_node); | 861 | object = rb_entry(_n, struct cachefiles_object, active_node); |
862 | 862 | ||
863 | if (object->dentry > victim) | 863 | if (object->dentry > victim) |
864 | _n = _n->rb_left; | 864 | _n = _n->rb_left; |
865 | else if (object->dentry < victim) | 865 | else if (object->dentry < victim) |
866 | _n = _n->rb_right; | 866 | _n = _n->rb_right; |
867 | else | 867 | else |
868 | goto object_in_use; | 868 | goto object_in_use; |
869 | } | 869 | } |
870 | 870 | ||
871 | read_unlock(&cache->active_lock); | 871 | read_unlock(&cache->active_lock); |
872 | 872 | ||
873 | //_leave(" = %p", victim); | 873 | //_leave(" = %p", victim); |
874 | return victim; | 874 | return victim; |
875 | 875 | ||
876 | object_in_use: | 876 | object_in_use: |
877 | read_unlock(&cache->active_lock); | 877 | read_unlock(&cache->active_lock); |
878 | mutex_unlock(&dir->d_inode->i_mutex); | 878 | mutex_unlock(&dir->d_inode->i_mutex); |
879 | dput(victim); | 879 | dput(victim); |
880 | //_leave(" = -EBUSY [in use]"); | 880 | //_leave(" = -EBUSY [in use]"); |
881 | return ERR_PTR(-EBUSY); | 881 | return ERR_PTR(-EBUSY); |
882 | 882 | ||
883 | lookup_error: | 883 | lookup_error: |
884 | mutex_unlock(&dir->d_inode->i_mutex); | 884 | mutex_unlock(&dir->d_inode->i_mutex); |
885 | ret = PTR_ERR(victim); | 885 | ret = PTR_ERR(victim); |
886 | if (ret == -ENOENT) { | 886 | if (ret == -ENOENT) { |
887 | /* file or dir now absent - probably retired by netfs */ | 887 | /* file or dir now absent - probably retired by netfs */ |
888 | _leave(" = -ESTALE [absent]"); | 888 | _leave(" = -ESTALE [absent]"); |
889 | return ERR_PTR(-ESTALE); | 889 | return ERR_PTR(-ESTALE); |
890 | } | 890 | } |
891 | 891 | ||
892 | if (ret == -EIO) { | 892 | if (ret == -EIO) { |
893 | cachefiles_io_error(cache, "Lookup failed"); | 893 | cachefiles_io_error(cache, "Lookup failed"); |
894 | } else if (ret != -ENOMEM) { | 894 | } else if (ret != -ENOMEM) { |
895 | pr_err("Internal error: %d", ret); | 895 | pr_err("Internal error: %d\n", ret); |
896 | ret = -EIO; | 896 | ret = -EIO; |
897 | } | 897 | } |
898 | 898 | ||
899 | _leave(" = %d", ret); | 899 | _leave(" = %d", ret); |
900 | return ERR_PTR(ret); | 900 | return ERR_PTR(ret); |
901 | } | 901 | } |
902 | 902 | ||
903 | /* | 903 | /* |
904 | * cull an object if it's not in use | 904 | * cull an object if it's not in use |
905 | * - called only by cache manager daemon | 905 | * - called only by cache manager daemon |
906 | */ | 906 | */ |
907 | int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, | 907 | int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, |
908 | char *filename) | 908 | char *filename) |
909 | { | 909 | { |
910 | struct dentry *victim; | 910 | struct dentry *victim; |
911 | int ret; | 911 | int ret; |
912 | 912 | ||
913 | _enter(",%*.*s/,%s", | 913 | _enter(",%*.*s/,%s", |
914 | dir->d_name.len, dir->d_name.len, dir->d_name.name, filename); | 914 | dir->d_name.len, dir->d_name.len, dir->d_name.name, filename); |
915 | 915 | ||
916 | victim = cachefiles_check_active(cache, dir, filename); | 916 | victim = cachefiles_check_active(cache, dir, filename); |
917 | if (IS_ERR(victim)) | 917 | if (IS_ERR(victim)) |
918 | return PTR_ERR(victim); | 918 | return PTR_ERR(victim); |
919 | 919 | ||
920 | _debug("victim -> %p %s", | 920 | _debug("victim -> %p %s", |
921 | victim, victim->d_inode ? "positive" : "negative"); | 921 | victim, victim->d_inode ? "positive" : "negative"); |
922 | 922 | ||
923 | /* okay... the victim is not being used so we can cull it | 923 | /* okay... the victim is not being used so we can cull it |
924 | * - start by marking it as stale | 924 | * - start by marking it as stale |
925 | */ | 925 | */ |
926 | _debug("victim is cullable"); | 926 | _debug("victim is cullable"); |
927 | 927 | ||
928 | ret = cachefiles_remove_object_xattr(cache, victim); | 928 | ret = cachefiles_remove_object_xattr(cache, victim); |
929 | if (ret < 0) | 929 | if (ret < 0) |
930 | goto error_unlock; | 930 | goto error_unlock; |
931 | 931 | ||
932 | /* actually remove the victim (drops the dir mutex) */ | 932 | /* actually remove the victim (drops the dir mutex) */ |
933 | _debug("bury"); | 933 | _debug("bury"); |
934 | 934 | ||
935 | ret = cachefiles_bury_object(cache, dir, victim, false); | 935 | ret = cachefiles_bury_object(cache, dir, victim, false); |
936 | if (ret < 0) | 936 | if (ret < 0) |
937 | goto error; | 937 | goto error; |
938 | 938 | ||
939 | dput(victim); | 939 | dput(victim); |
940 | _leave(" = 0"); | 940 | _leave(" = 0"); |
941 | return 0; | 941 | return 0; |
942 | 942 | ||
943 | error_unlock: | 943 | error_unlock: |
944 | mutex_unlock(&dir->d_inode->i_mutex); | 944 | mutex_unlock(&dir->d_inode->i_mutex); |
945 | error: | 945 | error: |
946 | dput(victim); | 946 | dput(victim); |
947 | if (ret == -ENOENT) { | 947 | if (ret == -ENOENT) { |
948 | /* file or dir now absent - probably retired by netfs */ | 948 | /* file or dir now absent - probably retired by netfs */ |
949 | _leave(" = -ESTALE [absent]"); | 949 | _leave(" = -ESTALE [absent]"); |
950 | return -ESTALE; | 950 | return -ESTALE; |
951 | } | 951 | } |
952 | 952 | ||
953 | if (ret != -ENOMEM) { | 953 | if (ret != -ENOMEM) { |
954 | pr_err("Internal error: %d", ret); | 954 | pr_err("Internal error: %d\n", ret); |
955 | ret = -EIO; | 955 | ret = -EIO; |
956 | } | 956 | } |
957 | 957 | ||
958 | _leave(" = %d", ret); | 958 | _leave(" = %d", ret); |
959 | return ret; | 959 | return ret; |
960 | } | 960 | } |
961 | 961 | ||
962 | /* | 962 | /* |
963 | * find out if an object is in use or not | 963 | * find out if an object is in use or not |
964 | * - called only by cache manager daemon | 964 | * - called only by cache manager daemon |
965 | * - returns -EBUSY or 0 to indicate whether an object is in use or not | 965 | * - returns -EBUSY or 0 to indicate whether an object is in use or not |
966 | */ | 966 | */ |
967 | int cachefiles_check_in_use(struct cachefiles_cache *cache, struct dentry *dir, | 967 | int cachefiles_check_in_use(struct cachefiles_cache *cache, struct dentry *dir, |
968 | char *filename) | 968 | char *filename) |
969 | { | 969 | { |
970 | struct dentry *victim; | 970 | struct dentry *victim; |
971 | 971 | ||
972 | //_enter(",%*.*s/,%s", | 972 | //_enter(",%*.*s/,%s", |
973 | // dir->d_name.len, dir->d_name.len, dir->d_name.name, filename); | 973 | // dir->d_name.len, dir->d_name.len, dir->d_name.name, filename); |
974 | 974 | ||
975 | victim = cachefiles_check_active(cache, dir, filename); | 975 | victim = cachefiles_check_active(cache, dir, filename); |
976 | if (IS_ERR(victim)) | 976 | if (IS_ERR(victim)) |
977 | return PTR_ERR(victim); | 977 | return PTR_ERR(victim); |
978 | 978 | ||
979 | mutex_unlock(&dir->d_inode->i_mutex); | 979 | mutex_unlock(&dir->d_inode->i_mutex); |
980 | dput(victim); | 980 | dput(victim); |
981 | //_leave(" = 0"); | 981 | //_leave(" = 0"); |
982 | return 0; | 982 | return 0; |
983 | } | 983 | } |
984 | 984 |
fs/cachefiles/xattr.c
1 | /* CacheFiles extended attribute management | 1 | /* CacheFiles extended attribute management |
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/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/file.h> | 14 | #include <linux/file.h> |
15 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
16 | #include <linux/fsnotify.h> | 16 | #include <linux/fsnotify.h> |
17 | #include <linux/quotaops.h> | 17 | #include <linux/quotaops.h> |
18 | #include <linux/xattr.h> | 18 | #include <linux/xattr.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include "internal.h" | 20 | #include "internal.h" |
21 | 21 | ||
22 | static const char cachefiles_xattr_cache[] = | 22 | static const char cachefiles_xattr_cache[] = |
23 | XATTR_USER_PREFIX "CacheFiles.cache"; | 23 | XATTR_USER_PREFIX "CacheFiles.cache"; |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * check the type label on an object | 26 | * check the type label on an object |
27 | * - done using xattrs | 27 | * - done using xattrs |
28 | */ | 28 | */ |
29 | int cachefiles_check_object_type(struct cachefiles_object *object) | 29 | int cachefiles_check_object_type(struct cachefiles_object *object) |
30 | { | 30 | { |
31 | struct dentry *dentry = object->dentry; | 31 | struct dentry *dentry = object->dentry; |
32 | char type[3], xtype[3]; | 32 | char type[3], xtype[3]; |
33 | int ret; | 33 | int ret; |
34 | 34 | ||
35 | ASSERT(dentry); | 35 | ASSERT(dentry); |
36 | ASSERT(dentry->d_inode); | 36 | ASSERT(dentry->d_inode); |
37 | 37 | ||
38 | if (!object->fscache.cookie) | 38 | if (!object->fscache.cookie) |
39 | strcpy(type, "C3"); | 39 | strcpy(type, "C3"); |
40 | else | 40 | else |
41 | snprintf(type, 3, "%02x", object->fscache.cookie->def->type); | 41 | snprintf(type, 3, "%02x", object->fscache.cookie->def->type); |
42 | 42 | ||
43 | _enter("%p{%s}", object, type); | 43 | _enter("%p{%s}", object, type); |
44 | 44 | ||
45 | /* attempt to install a type label directly */ | 45 | /* attempt to install a type label directly */ |
46 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2, | 46 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2, |
47 | XATTR_CREATE); | 47 | XATTR_CREATE); |
48 | if (ret == 0) { | 48 | if (ret == 0) { |
49 | _debug("SET"); /* we succeeded */ | 49 | _debug("SET"); /* we succeeded */ |
50 | goto error; | 50 | goto error; |
51 | } | 51 | } |
52 | 52 | ||
53 | if (ret != -EEXIST) { | 53 | if (ret != -EEXIST) { |
54 | pr_err("Can't set xattr on %*.*s [%lu] (err %d)", | 54 | pr_err("Can't set xattr on %*.*s [%lu] (err %d)\n", |
55 | dentry->d_name.len, dentry->d_name.len, | 55 | dentry->d_name.len, dentry->d_name.len, |
56 | dentry->d_name.name, dentry->d_inode->i_ino, | 56 | dentry->d_name.name, dentry->d_inode->i_ino, |
57 | -ret); | 57 | -ret); |
58 | goto error; | 58 | goto error; |
59 | } | 59 | } |
60 | 60 | ||
61 | /* read the current type label */ | 61 | /* read the current type label */ |
62 | ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3); | 62 | ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3); |
63 | if (ret < 0) { | 63 | if (ret < 0) { |
64 | if (ret == -ERANGE) | 64 | if (ret == -ERANGE) |
65 | goto bad_type_length; | 65 | goto bad_type_length; |
66 | 66 | ||
67 | pr_err("Can't read xattr on %*.*s [%lu] (err %d)", | 67 | pr_err("Can't read xattr on %*.*s [%lu] (err %d)\n", |
68 | dentry->d_name.len, dentry->d_name.len, | 68 | dentry->d_name.len, dentry->d_name.len, |
69 | dentry->d_name.name, dentry->d_inode->i_ino, | 69 | dentry->d_name.name, dentry->d_inode->i_ino, |
70 | -ret); | 70 | -ret); |
71 | goto error; | 71 | goto error; |
72 | } | 72 | } |
73 | 73 | ||
74 | /* check the type is what we're expecting */ | 74 | /* check the type is what we're expecting */ |
75 | if (ret != 2) | 75 | if (ret != 2) |
76 | goto bad_type_length; | 76 | goto bad_type_length; |
77 | 77 | ||
78 | if (xtype[0] != type[0] || xtype[1] != type[1]) | 78 | if (xtype[0] != type[0] || xtype[1] != type[1]) |
79 | goto bad_type; | 79 | goto bad_type; |
80 | 80 | ||
81 | ret = 0; | 81 | ret = 0; |
82 | 82 | ||
83 | error: | 83 | error: |
84 | _leave(" = %d", ret); | 84 | _leave(" = %d", ret); |
85 | return ret; | 85 | return ret; |
86 | 86 | ||
87 | bad_type_length: | 87 | bad_type_length: |
88 | pr_err("Cache object %lu type xattr length incorrect", | 88 | pr_err("Cache object %lu type xattr length incorrect\n", |
89 | dentry->d_inode->i_ino); | 89 | dentry->d_inode->i_ino); |
90 | ret = -EIO; | 90 | ret = -EIO; |
91 | goto error; | 91 | goto error; |
92 | 92 | ||
93 | bad_type: | 93 | bad_type: |
94 | xtype[2] = 0; | 94 | xtype[2] = 0; |
95 | pr_err("Cache object %*.*s [%lu] type %s not %s", | 95 | pr_err("Cache object %*.*s [%lu] type %s not %s\n", |
96 | dentry->d_name.len, dentry->d_name.len, | 96 | dentry->d_name.len, dentry->d_name.len, |
97 | dentry->d_name.name, dentry->d_inode->i_ino, | 97 | dentry->d_name.name, dentry->d_inode->i_ino, |
98 | xtype, type); | 98 | xtype, type); |
99 | ret = -EIO; | 99 | ret = -EIO; |
100 | goto error; | 100 | goto error; |
101 | } | 101 | } |
102 | 102 | ||
103 | /* | 103 | /* |
104 | * set the state xattr on a cache file | 104 | * set the state xattr on a cache file |
105 | */ | 105 | */ |
106 | int cachefiles_set_object_xattr(struct cachefiles_object *object, | 106 | int cachefiles_set_object_xattr(struct cachefiles_object *object, |
107 | struct cachefiles_xattr *auxdata) | 107 | struct cachefiles_xattr *auxdata) |
108 | { | 108 | { |
109 | struct dentry *dentry = object->dentry; | 109 | struct dentry *dentry = object->dentry; |
110 | int ret; | 110 | int ret; |
111 | 111 | ||
112 | ASSERT(dentry); | 112 | ASSERT(dentry); |
113 | 113 | ||
114 | _enter("%p,#%d", object, auxdata->len); | 114 | _enter("%p,#%d", object, auxdata->len); |
115 | 115 | ||
116 | /* attempt to install the cache metadata directly */ | 116 | /* attempt to install the cache metadata directly */ |
117 | _debug("SET #%u", auxdata->len); | 117 | _debug("SET #%u", auxdata->len); |
118 | 118 | ||
119 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, | 119 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, |
120 | &auxdata->type, auxdata->len, | 120 | &auxdata->type, auxdata->len, |
121 | XATTR_CREATE); | 121 | XATTR_CREATE); |
122 | if (ret < 0 && ret != -ENOMEM) | 122 | if (ret < 0 && ret != -ENOMEM) |
123 | cachefiles_io_error_obj( | 123 | cachefiles_io_error_obj( |
124 | object, | 124 | object, |
125 | "Failed to set xattr with error %d", ret); | 125 | "Failed to set xattr with error %d", ret); |
126 | 126 | ||
127 | _leave(" = %d", ret); | 127 | _leave(" = %d", ret); |
128 | return ret; | 128 | return ret; |
129 | } | 129 | } |
130 | 130 | ||
131 | /* | 131 | /* |
132 | * update the state xattr on a cache file | 132 | * update the state xattr on a cache file |
133 | */ | 133 | */ |
134 | int cachefiles_update_object_xattr(struct cachefiles_object *object, | 134 | int cachefiles_update_object_xattr(struct cachefiles_object *object, |
135 | struct cachefiles_xattr *auxdata) | 135 | struct cachefiles_xattr *auxdata) |
136 | { | 136 | { |
137 | struct dentry *dentry = object->dentry; | 137 | struct dentry *dentry = object->dentry; |
138 | int ret; | 138 | int ret; |
139 | 139 | ||
140 | ASSERT(dentry); | 140 | ASSERT(dentry); |
141 | 141 | ||
142 | _enter("%p,#%d", object, auxdata->len); | 142 | _enter("%p,#%d", object, auxdata->len); |
143 | 143 | ||
144 | /* attempt to install the cache metadata directly */ | 144 | /* attempt to install the cache metadata directly */ |
145 | _debug("SET #%u", auxdata->len); | 145 | _debug("SET #%u", auxdata->len); |
146 | 146 | ||
147 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, | 147 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, |
148 | &auxdata->type, auxdata->len, | 148 | &auxdata->type, auxdata->len, |
149 | XATTR_REPLACE); | 149 | XATTR_REPLACE); |
150 | if (ret < 0 && ret != -ENOMEM) | 150 | if (ret < 0 && ret != -ENOMEM) |
151 | cachefiles_io_error_obj( | 151 | cachefiles_io_error_obj( |
152 | object, | 152 | object, |
153 | "Failed to update xattr with error %d", ret); | 153 | "Failed to update xattr with error %d", ret); |
154 | 154 | ||
155 | _leave(" = %d", ret); | 155 | _leave(" = %d", ret); |
156 | return ret; | 156 | return ret; |
157 | } | 157 | } |
158 | 158 | ||
159 | /* | 159 | /* |
160 | * check the consistency between the backing cache and the FS-Cache cookie | 160 | * check the consistency between the backing cache and the FS-Cache cookie |
161 | */ | 161 | */ |
162 | int cachefiles_check_auxdata(struct cachefiles_object *object) | 162 | int cachefiles_check_auxdata(struct cachefiles_object *object) |
163 | { | 163 | { |
164 | struct cachefiles_xattr *auxbuf; | 164 | struct cachefiles_xattr *auxbuf; |
165 | enum fscache_checkaux validity; | 165 | enum fscache_checkaux validity; |
166 | struct dentry *dentry = object->dentry; | 166 | struct dentry *dentry = object->dentry; |
167 | ssize_t xlen; | 167 | ssize_t xlen; |
168 | int ret; | 168 | int ret; |
169 | 169 | ||
170 | ASSERT(dentry); | 170 | ASSERT(dentry); |
171 | ASSERT(dentry->d_inode); | 171 | ASSERT(dentry->d_inode); |
172 | ASSERT(object->fscache.cookie->def->check_aux); | 172 | ASSERT(object->fscache.cookie->def->check_aux); |
173 | 173 | ||
174 | auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL); | 174 | auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL); |
175 | if (!auxbuf) | 175 | if (!auxbuf) |
176 | return -ENOMEM; | 176 | return -ENOMEM; |
177 | 177 | ||
178 | xlen = vfs_getxattr(dentry, cachefiles_xattr_cache, | 178 | xlen = vfs_getxattr(dentry, cachefiles_xattr_cache, |
179 | &auxbuf->type, 512 + 1); | 179 | &auxbuf->type, 512 + 1); |
180 | ret = -ESTALE; | 180 | ret = -ESTALE; |
181 | if (xlen < 1 || | 181 | if (xlen < 1 || |
182 | auxbuf->type != object->fscache.cookie->def->type) | 182 | auxbuf->type != object->fscache.cookie->def->type) |
183 | goto error; | 183 | goto error; |
184 | 184 | ||
185 | xlen--; | 185 | xlen--; |
186 | validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen); | 186 | validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen); |
187 | if (validity != FSCACHE_CHECKAUX_OKAY) | 187 | if (validity != FSCACHE_CHECKAUX_OKAY) |
188 | goto error; | 188 | goto error; |
189 | 189 | ||
190 | ret = 0; | 190 | ret = 0; |
191 | error: | 191 | error: |
192 | kfree(auxbuf); | 192 | kfree(auxbuf); |
193 | return ret; | 193 | return ret; |
194 | } | 194 | } |
195 | 195 | ||
196 | /* | 196 | /* |
197 | * check the state xattr on a cache file | 197 | * check the state xattr on a cache file |
198 | * - return -ESTALE if the object should be deleted | 198 | * - return -ESTALE if the object should be deleted |
199 | */ | 199 | */ |
200 | int cachefiles_check_object_xattr(struct cachefiles_object *object, | 200 | int cachefiles_check_object_xattr(struct cachefiles_object *object, |
201 | struct cachefiles_xattr *auxdata) | 201 | struct cachefiles_xattr *auxdata) |
202 | { | 202 | { |
203 | struct cachefiles_xattr *auxbuf; | 203 | struct cachefiles_xattr *auxbuf; |
204 | struct dentry *dentry = object->dentry; | 204 | struct dentry *dentry = object->dentry; |
205 | int ret; | 205 | int ret; |
206 | 206 | ||
207 | _enter("%p,#%d", object, auxdata->len); | 207 | _enter("%p,#%d", object, auxdata->len); |
208 | 208 | ||
209 | ASSERT(dentry); | 209 | ASSERT(dentry); |
210 | ASSERT(dentry->d_inode); | 210 | ASSERT(dentry->d_inode); |
211 | 211 | ||
212 | auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp); | 212 | auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp); |
213 | if (!auxbuf) { | 213 | if (!auxbuf) { |
214 | _leave(" = -ENOMEM"); | 214 | _leave(" = -ENOMEM"); |
215 | return -ENOMEM; | 215 | return -ENOMEM; |
216 | } | 216 | } |
217 | 217 | ||
218 | /* read the current type label */ | 218 | /* read the current type label */ |
219 | ret = vfs_getxattr(dentry, cachefiles_xattr_cache, | 219 | ret = vfs_getxattr(dentry, cachefiles_xattr_cache, |
220 | &auxbuf->type, 512 + 1); | 220 | &auxbuf->type, 512 + 1); |
221 | if (ret < 0) { | 221 | if (ret < 0) { |
222 | if (ret == -ENODATA) | 222 | if (ret == -ENODATA) |
223 | goto stale; /* no attribute - power went off | 223 | goto stale; /* no attribute - power went off |
224 | * mid-cull? */ | 224 | * mid-cull? */ |
225 | 225 | ||
226 | if (ret == -ERANGE) | 226 | if (ret == -ERANGE) |
227 | goto bad_type_length; | 227 | goto bad_type_length; |
228 | 228 | ||
229 | cachefiles_io_error_obj(object, | 229 | cachefiles_io_error_obj(object, |
230 | "Can't read xattr on %lu (err %d)", | 230 | "Can't read xattr on %lu (err %d)", |
231 | dentry->d_inode->i_ino, -ret); | 231 | dentry->d_inode->i_ino, -ret); |
232 | goto error; | 232 | goto error; |
233 | } | 233 | } |
234 | 234 | ||
235 | /* check the on-disk object */ | 235 | /* check the on-disk object */ |
236 | if (ret < 1) | 236 | if (ret < 1) |
237 | goto bad_type_length; | 237 | goto bad_type_length; |
238 | 238 | ||
239 | if (auxbuf->type != auxdata->type) | 239 | if (auxbuf->type != auxdata->type) |
240 | goto stale; | 240 | goto stale; |
241 | 241 | ||
242 | auxbuf->len = ret; | 242 | auxbuf->len = ret; |
243 | 243 | ||
244 | /* consult the netfs */ | 244 | /* consult the netfs */ |
245 | if (object->fscache.cookie->def->check_aux) { | 245 | if (object->fscache.cookie->def->check_aux) { |
246 | enum fscache_checkaux result; | 246 | enum fscache_checkaux result; |
247 | unsigned int dlen; | 247 | unsigned int dlen; |
248 | 248 | ||
249 | dlen = auxbuf->len - 1; | 249 | dlen = auxbuf->len - 1; |
250 | 250 | ||
251 | _debug("checkaux %s #%u", | 251 | _debug("checkaux %s #%u", |
252 | object->fscache.cookie->def->name, dlen); | 252 | object->fscache.cookie->def->name, dlen); |
253 | 253 | ||
254 | result = fscache_check_aux(&object->fscache, | 254 | result = fscache_check_aux(&object->fscache, |
255 | &auxbuf->data, dlen); | 255 | &auxbuf->data, dlen); |
256 | 256 | ||
257 | switch (result) { | 257 | switch (result) { |
258 | /* entry okay as is */ | 258 | /* entry okay as is */ |
259 | case FSCACHE_CHECKAUX_OKAY: | 259 | case FSCACHE_CHECKAUX_OKAY: |
260 | goto okay; | 260 | goto okay; |
261 | 261 | ||
262 | /* entry requires update */ | 262 | /* entry requires update */ |
263 | case FSCACHE_CHECKAUX_NEEDS_UPDATE: | 263 | case FSCACHE_CHECKAUX_NEEDS_UPDATE: |
264 | break; | 264 | break; |
265 | 265 | ||
266 | /* entry requires deletion */ | 266 | /* entry requires deletion */ |
267 | case FSCACHE_CHECKAUX_OBSOLETE: | 267 | case FSCACHE_CHECKAUX_OBSOLETE: |
268 | goto stale; | 268 | goto stale; |
269 | 269 | ||
270 | default: | 270 | default: |
271 | BUG(); | 271 | BUG(); |
272 | } | 272 | } |
273 | 273 | ||
274 | /* update the current label */ | 274 | /* update the current label */ |
275 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, | 275 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, |
276 | &auxdata->type, auxdata->len, | 276 | &auxdata->type, auxdata->len, |
277 | XATTR_REPLACE); | 277 | XATTR_REPLACE); |
278 | if (ret < 0) { | 278 | if (ret < 0) { |
279 | cachefiles_io_error_obj(object, | 279 | cachefiles_io_error_obj(object, |
280 | "Can't update xattr on %lu" | 280 | "Can't update xattr on %lu" |
281 | " (error %d)", | 281 | " (error %d)", |
282 | dentry->d_inode->i_ino, -ret); | 282 | dentry->d_inode->i_ino, -ret); |
283 | goto error; | 283 | goto error; |
284 | } | 284 | } |
285 | } | 285 | } |
286 | 286 | ||
287 | okay: | 287 | okay: |
288 | ret = 0; | 288 | ret = 0; |
289 | 289 | ||
290 | error: | 290 | error: |
291 | kfree(auxbuf); | 291 | kfree(auxbuf); |
292 | _leave(" = %d", ret); | 292 | _leave(" = %d", ret); |
293 | return ret; | 293 | return ret; |
294 | 294 | ||
295 | bad_type_length: | 295 | bad_type_length: |
296 | pr_err("Cache object %lu xattr length incorrect", | 296 | pr_err("Cache object %lu xattr length incorrect\n", |
297 | dentry->d_inode->i_ino); | 297 | dentry->d_inode->i_ino); |
298 | ret = -EIO; | 298 | ret = -EIO; |
299 | goto error; | 299 | goto error; |
300 | 300 | ||
301 | stale: | 301 | stale: |
302 | ret = -ESTALE; | 302 | ret = -ESTALE; |
303 | goto error; | 303 | goto error; |
304 | } | 304 | } |
305 | 305 | ||
306 | /* | 306 | /* |
307 | * remove the object's xattr to mark it stale | 307 | * remove the object's xattr to mark it stale |
308 | */ | 308 | */ |
309 | int cachefiles_remove_object_xattr(struct cachefiles_cache *cache, | 309 | int cachefiles_remove_object_xattr(struct cachefiles_cache *cache, |
310 | struct dentry *dentry) | 310 | struct dentry *dentry) |
311 | { | 311 | { |
312 | int ret; | 312 | int ret; |
313 | 313 | ||
314 | ret = vfs_removexattr(dentry, cachefiles_xattr_cache); | 314 | ret = vfs_removexattr(dentry, cachefiles_xattr_cache); |
315 | if (ret < 0) { | 315 | if (ret < 0) { |
316 | if (ret == -ENOENT || ret == -ENODATA) | 316 | if (ret == -ENOENT || ret == -ENODATA) |
317 | ret = 0; | 317 | ret = 0; |
318 | else if (ret != -ENOMEM) | 318 | else if (ret != -ENOMEM) |
319 | cachefiles_io_error(cache, | 319 | cachefiles_io_error(cache, |
320 | "Can't remove xattr from %lu" | 320 | "Can't remove xattr from %lu" |
321 | " (error %d)", | 321 | " (error %d)", |
322 | dentry->d_inode->i_ino, -ret); | 322 | dentry->d_inode->i_ino, -ret); |
323 | } | 323 | } |
324 | 324 | ||
325 | _leave(" = %d", ret); | 325 | _leave(" = %d", ret); |
326 | return ret; | 326 | return ret; |
327 | } | 327 | } |
328 | 328 |