]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Jeff Mahoney <jeffm@suse.com> |
2 | Subject: reiserfs: Clean up xattrs when REISERFS_FS_XATTR is unset | |
3 | ||
4 | The current reiserfs xattr implementation will not clean up old xattr | |
5 | files if files are deleted when REISERFS_FS_XATTR is unset. This results | |
6 | in inaccessible lost files, wasting space. | |
7 | ||
8 | This patch compiles in basic xattr knowledge, such as how to delete them and | |
9 | change ownership for quota tracking. If the file system has never used | |
10 | xattrs, then the operation is quite fast: it returns immediately when | |
11 | it sees there is no .reiserfs_priv directory. | |
12 | ||
13 | Signed-off-by: Jeff Mahoney <jeffm@suse.com> | |
14 | --- | |
15 | fs/reiserfs/Makefile | 4 | |
16 | fs/reiserfs/xattr.c | 801 +++++++++++++++++++++-------------------- | |
17 | include/linux/reiserfs_fs_sb.h | 2 | |
18 | include/linux/reiserfs_xattr.h | 29 - | |
19 | 4 files changed, 423 insertions(+), 413 deletions(-) | |
20 | ||
21 | --- a/fs/reiserfs/Makefile | |
22 | +++ b/fs/reiserfs/Makefile | |
23 | @@ -7,10 +7,10 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o | |
24 | reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ | |
25 | super.o prints.o objectid.o lbalance.o ibalance.o stree.o \ | |
26 | hashes.o tail_conversion.o journal.o resize.o \ | |
27 | - item_ops.o ioctl.o procfs.o | |
28 | + item_ops.o ioctl.o procfs.o xattr.o | |
29 | ||
30 | ifeq ($(CONFIG_REISERFS_FS_XATTR),y) | |
31 | -reiserfs-objs += xattr.o xattr_user.o xattr_trusted.o | |
32 | +reiserfs-objs += xattr_user.o xattr_trusted.o | |
33 | endif | |
34 | ||
35 | ifeq ($(CONFIG_REISERFS_FS_SECURITY),y) | |
36 | --- a/fs/reiserfs/xattr.c | |
37 | +++ b/fs/reiserfs/xattr.c | |
38 | @@ -50,9 +50,6 @@ | |
39 | #define PRIVROOT_NAME ".reiserfs_priv" | |
40 | #define XAROOT_NAME "xattrs" | |
41 | ||
42 | -static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char | |
43 | - *prefix); | |
44 | - | |
45 | /* Returns the dentry referring to the root of the extended attribute | |
46 | * directory tree. If it has already been retrieved, it is used. If it | |
47 | * hasn't been created and the flags indicate creation is allowed, we | |
48 | @@ -143,60 +140,6 @@ static struct dentry *open_xa_dir(const | |
49 | return xadir; | |
50 | } | |
51 | ||
52 | -/* Returns a dentry corresponding to a specific extended attribute file | |
53 | - * for the inode. If flags allow, the file is created. Otherwise, a | |
54 | - * valid or negative dentry, or an error is returned. */ | |
55 | -static struct dentry *get_xa_file_dentry(const struct inode *inode, | |
56 | - const char *name, int flags) | |
57 | -{ | |
58 | - struct dentry *xadir, *xafile; | |
59 | - int err = 0; | |
60 | - | |
61 | - xadir = open_xa_dir(inode, flags); | |
62 | - if (IS_ERR(xadir)) { | |
63 | - return ERR_CAST(xadir); | |
64 | - } else if (xadir && !xadir->d_inode) { | |
65 | - dput(xadir); | |
66 | - return ERR_PTR(-ENODATA); | |
67 | - } | |
68 | - | |
69 | - xafile = lookup_one_len(name, xadir, strlen(name)); | |
70 | - if (IS_ERR(xafile)) { | |
71 | - dput(xadir); | |
72 | - return ERR_CAST(xafile); | |
73 | - } | |
74 | - | |
75 | - if (xafile->d_inode) { /* file exists */ | |
76 | - if (flags & XATTR_CREATE) { | |
77 | - err = -EEXIST; | |
78 | - dput(xafile); | |
79 | - goto out; | |
80 | - } | |
81 | - } else if (flags & XATTR_REPLACE || flags & FL_READONLY) { | |
82 | - goto out; | |
83 | - } else { | |
84 | - /* inode->i_mutex is down, so nothing else can try to create | |
85 | - * the same xattr */ | |
86 | - err = xadir->d_inode->i_op->create(xadir->d_inode, xafile, | |
87 | - 0700 | S_IFREG, NULL); | |
88 | - | |
89 | - if (err) { | |
90 | - dput(xafile); | |
91 | - goto out; | |
92 | - } | |
93 | - } | |
94 | - | |
95 | - out: | |
96 | - dput(xadir); | |
97 | - if (err) | |
98 | - xafile = ERR_PTR(err); | |
99 | - else if (!xafile->d_inode) { | |
100 | - dput(xafile); | |
101 | - xafile = ERR_PTR(-ENODATA); | |
102 | - } | |
103 | - return xafile; | |
104 | -} | |
105 | - | |
106 | /* | |
107 | * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but | |
108 | * we need to drop the path before calling the filldir struct. That | |
109 | @@ -369,6 +312,251 @@ int xattr_readdir(struct inode *inode, f | |
110 | return res; | |
111 | } | |
112 | ||
113 | +static int | |
114 | +__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) | |
115 | +{ | |
116 | + struct dentry *dentry; | |
117 | + struct inode *dir = xadir->d_inode; | |
118 | + int err = 0; | |
119 | + | |
120 | + dentry = lookup_one_len(name, xadir, namelen); | |
121 | + if (IS_ERR(dentry)) { | |
122 | + err = PTR_ERR(dentry); | |
123 | + goto out; | |
124 | + } else if (!dentry->d_inode) { | |
125 | + err = -ENODATA; | |
126 | + goto out_file; | |
127 | + } | |
128 | + | |
129 | + /* Skip directories.. */ | |
130 | + if (S_ISDIR(dentry->d_inode->i_mode)) | |
131 | + goto out_file; | |
132 | + | |
133 | + if (!IS_PRIVATE(dentry->d_inode)) { | |
134 | + reiserfs_error(dir->i_sb, "jdm-20003", | |
135 | + "OID %08x [%.*s/%.*s] doesn't have " | |
136 | + "priv flag set [parent is %sset].", | |
137 | + le32_to_cpu(INODE_PKEY(dentry->d_inode)-> | |
138 | + k_objectid), xadir->d_name.len, | |
139 | + xadir->d_name.name, namelen, name, | |
140 | + IS_PRIVATE(xadir->d_inode) ? "" : | |
141 | + "not "); | |
142 | + dput(dentry); | |
143 | + return -EIO; | |
144 | + } | |
145 | + | |
146 | + err = dir->i_op->unlink(dir, dentry); | |
147 | + if (!err) | |
148 | + d_delete(dentry); | |
149 | + | |
150 | +out_file: | |
151 | + dput(dentry); | |
152 | + | |
153 | +out: | |
154 | + return err; | |
155 | +} | |
156 | + | |
157 | +/* The following are side effects of other operations that aren't explicitly | |
158 | + * modifying extended attributes. This includes operations such as permissions | |
159 | + * or ownership changes, object deletions, etc. */ | |
160 | + | |
161 | +static int | |
162 | +reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, | |
163 | + loff_t offset, u64 ino, unsigned int d_type) | |
164 | +{ | |
165 | + struct dentry *xadir = (struct dentry *)buf; | |
166 | + | |
167 | + return __reiserfs_xattr_del(xadir, name, namelen); | |
168 | + | |
169 | +} | |
170 | + | |
171 | +/* This is called w/ inode->i_mutex downed */ | |
172 | +int reiserfs_delete_xattrs(struct inode *inode) | |
173 | +{ | |
174 | + struct dentry *dir, *root; | |
175 | + int err = 0; | |
176 | + | |
177 | + /* Skip out, an xattr has no xattrs associated with it */ | |
178 | + if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) | |
179 | + return 0; | |
180 | + | |
181 | + reiserfs_read_lock_xattrs(inode->i_sb); | |
182 | + dir = open_xa_dir(inode, FL_READONLY); | |
183 | + reiserfs_read_unlock_xattrs(inode->i_sb); | |
184 | + if (IS_ERR(dir)) { | |
185 | + err = PTR_ERR(dir); | |
186 | + goto out; | |
187 | + } else if (!dir->d_inode) { | |
188 | + dput(dir); | |
189 | + return 0; | |
190 | + } | |
191 | + | |
192 | + lock_kernel(); | |
193 | + err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); | |
194 | + if (err) { | |
195 | + unlock_kernel(); | |
196 | + goto out_dir; | |
197 | + } | |
198 | + | |
199 | + /* Leftovers besides . and .. -- that's not good. */ | |
200 | + if (dir->d_inode->i_nlink <= 2) { | |
201 | + root = get_xa_root(inode->i_sb, XATTR_REPLACE); | |
202 | + reiserfs_write_lock_xattrs(inode->i_sb); | |
203 | + err = vfs_rmdir(root->d_inode, dir); | |
204 | + reiserfs_write_unlock_xattrs(inode->i_sb); | |
205 | + dput(root); | |
206 | + } else { | |
207 | + reiserfs_warning(inode->i_sb, "jdm-20006", | |
208 | + "Couldn't remove all entries in directory"); | |
209 | + } | |
210 | + unlock_kernel(); | |
211 | + | |
212 | +out_dir: | |
213 | + dput(dir); | |
214 | + | |
215 | +out: | |
216 | + if (!err) | |
217 | + REISERFS_I(inode)->i_flags = | |
218 | + REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; | |
219 | + return err; | |
220 | +} | |
221 | + | |
222 | +struct reiserfs_chown_buf { | |
223 | + struct inode *inode; | |
224 | + struct dentry *xadir; | |
225 | + struct iattr *attrs; | |
226 | +}; | |
227 | + | |
228 | +/* XXX: If there is a better way to do this, I'd love to hear about it */ | |
229 | +static int | |
230 | +reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, | |
231 | + loff_t offset, u64 ino, unsigned int d_type) | |
232 | +{ | |
233 | + struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; | |
234 | + struct dentry *xafile, *xadir = chown_buf->xadir; | |
235 | + struct iattr *attrs = chown_buf->attrs; | |
236 | + int err = 0; | |
237 | + | |
238 | + xafile = lookup_one_len(name, xadir, namelen); | |
239 | + if (IS_ERR(xafile)) | |
240 | + return PTR_ERR(xafile); | |
241 | + else if (!xafile->d_inode) { | |
242 | + dput(xafile); | |
243 | + return -ENODATA; | |
244 | + } | |
245 | + | |
246 | + if (!S_ISDIR(xafile->d_inode->i_mode)) | |
247 | + err = notify_change(xafile, attrs); | |
248 | + dput(xafile); | |
249 | + | |
250 | + return err; | |
251 | +} | |
252 | + | |
253 | +int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) | |
254 | +{ | |
255 | + struct dentry *dir; | |
256 | + int err = 0; | |
257 | + struct reiserfs_chown_buf buf; | |
258 | + unsigned int ia_valid = attrs->ia_valid; | |
259 | + | |
260 | + /* Skip out, an xattr has no xattrs associated with it */ | |
261 | + if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) | |
262 | + return 0; | |
263 | + | |
264 | + reiserfs_read_lock_xattrs(inode->i_sb); | |
265 | + dir = open_xa_dir(inode, FL_READONLY); | |
266 | + reiserfs_read_unlock_xattrs(inode->i_sb); | |
267 | + if (IS_ERR(dir)) { | |
268 | + if (PTR_ERR(dir) != -ENODATA) | |
269 | + err = PTR_ERR(dir); | |
270 | + goto out; | |
271 | + } else if (!dir->d_inode) { | |
272 | + dput(dir); | |
273 | + goto out; | |
274 | + } | |
275 | + | |
276 | + lock_kernel(); | |
277 | + | |
278 | + attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); | |
279 | + buf.xadir = dir; | |
280 | + buf.attrs = attrs; | |
281 | + buf.inode = inode; | |
282 | + | |
283 | + err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); | |
284 | + if (err) { | |
285 | + unlock_kernel(); | |
286 | + goto out_dir; | |
287 | + } | |
288 | + | |
289 | + err = notify_change(dir, attrs); | |
290 | + unlock_kernel(); | |
291 | + | |
292 | +out_dir: | |
293 | + dput(dir); | |
294 | + | |
295 | +out: | |
296 | + attrs->ia_valid = ia_valid; | |
297 | + return err; | |
298 | +} | |
299 | + | |
300 | +#ifdef CONFIG_REISERFS_FS_XATTR | |
301 | +static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char | |
302 | + *prefix); | |
303 | + | |
304 | +/* Returns a dentry corresponding to a specific extended attribute file | |
305 | + * for the inode. If flags allow, the file is created. Otherwise, a | |
306 | + * valid or negative dentry, or an error is returned. */ | |
307 | +static struct dentry *get_xa_file_dentry(const struct inode *inode, | |
308 | + const char *name, int flags) | |
309 | +{ | |
310 | + struct dentry *xadir, *xafile; | |
311 | + int err = 0; | |
312 | + | |
313 | + xadir = open_xa_dir(inode, flags); | |
314 | + if (IS_ERR(xadir)) { | |
315 | + return ERR_CAST(xadir); | |
316 | + } else if (xadir && !xadir->d_inode) { | |
317 | + dput(xadir); | |
318 | + return ERR_PTR(-ENODATA); | |
319 | + } | |
320 | + | |
321 | + xafile = lookup_one_len(name, xadir, strlen(name)); | |
322 | + if (IS_ERR(xafile)) { | |
323 | + dput(xadir); | |
324 | + return ERR_CAST(xafile); | |
325 | + } | |
326 | + | |
327 | + if (xafile->d_inode) { /* file exists */ | |
328 | + if (flags & XATTR_CREATE) { | |
329 | + err = -EEXIST; | |
330 | + dput(xafile); | |
331 | + goto out; | |
332 | + } | |
333 | + } else if (flags & XATTR_REPLACE || flags & FL_READONLY) { | |
334 | + goto out; | |
335 | + } else { | |
336 | + /* inode->i_mutex is down, so nothing else can try to create | |
337 | + * the same xattr */ | |
338 | + err = xadir->d_inode->i_op->create(xadir->d_inode, xafile, | |
339 | + 0700 | S_IFREG, NULL); | |
340 | + | |
341 | + if (err) { | |
342 | + dput(xafile); | |
343 | + goto out; | |
344 | + } | |
345 | + } | |
346 | + | |
347 | +out: | |
348 | + dput(xadir); | |
349 | + if (err) | |
350 | + xafile = ERR_PTR(err); | |
351 | + else if (!xafile->d_inode) { | |
352 | + dput(xafile); | |
353 | + xafile = ERR_PTR(-ENODATA); | |
354 | + } | |
355 | + return xafile; | |
356 | +} | |
357 | + | |
358 | /* Internal operations on file data */ | |
359 | static inline void reiserfs_put_page(struct page *page) | |
360 | { | |
361 | @@ -554,274 +742,85 @@ reiserfs_xattr_get(const struct inode *i | |
362 | goto out_dput; | |
363 | } | |
364 | ||
365 | - while (file_pos < isize) { | |
366 | - size_t chunk; | |
367 | - char *data; | |
368 | - size_t skip = 0; | |
369 | - if (isize - file_pos > PAGE_CACHE_SIZE) | |
370 | - chunk = PAGE_CACHE_SIZE; | |
371 | - else | |
372 | - chunk = isize - file_pos; | |
373 | - | |
374 | - page = reiserfs_get_page(dentry->d_inode, file_pos); | |
375 | - if (IS_ERR(page)) { | |
376 | - err = PTR_ERR(page); | |
377 | - goto out_dput; | |
378 | - } | |
379 | - | |
380 | - lock_page(page); | |
381 | - data = page_address(page); | |
382 | - if (file_pos == 0) { | |
383 | - struct reiserfs_xattr_header *rxh = | |
384 | - (struct reiserfs_xattr_header *)data; | |
385 | - skip = file_pos = sizeof(struct reiserfs_xattr_header); | |
386 | - chunk -= skip; | |
387 | - /* Magic doesn't match up.. */ | |
388 | - if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) { | |
389 | - unlock_page(page); | |
390 | - reiserfs_put_page(page); | |
391 | - reiserfs_warning(inode->i_sb, "jdm-20001", | |
392 | - "Invalid magic for xattr (%s) " | |
393 | - "associated with %k", name, | |
394 | - INODE_PKEY(inode)); | |
395 | - err = -EIO; | |
396 | - goto out_dput; | |
397 | - } | |
398 | - hash = le32_to_cpu(rxh->h_hash); | |
399 | - } | |
400 | - memcpy(buffer + buffer_pos, data + skip, chunk); | |
401 | - unlock_page(page); | |
402 | - reiserfs_put_page(page); | |
403 | - file_pos += chunk; | |
404 | - buffer_pos += chunk; | |
405 | - skip = 0; | |
406 | - } | |
407 | - err = isize - sizeof(struct reiserfs_xattr_header); | |
408 | - | |
409 | - if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) != | |
410 | - hash) { | |
411 | - reiserfs_warning(inode->i_sb, "jdm-20002", | |
412 | - "Invalid hash for xattr (%s) associated " | |
413 | - "with %k", name, INODE_PKEY(inode)); | |
414 | - err = -EIO; | |
415 | - } | |
416 | - | |
417 | - out_dput: | |
418 | - dput(dentry); | |
419 | - | |
420 | - out: | |
421 | - return err; | |
422 | -} | |
423 | - | |
424 | -static int | |
425 | -__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) | |
426 | -{ | |
427 | - struct dentry *dentry; | |
428 | - struct inode *dir = xadir->d_inode; | |
429 | - int err = 0; | |
430 | - | |
431 | - dentry = lookup_one_len(name, xadir, namelen); | |
432 | - if (IS_ERR(dentry)) { | |
433 | - err = PTR_ERR(dentry); | |
434 | - goto out; | |
435 | - } else if (!dentry->d_inode) { | |
436 | - err = -ENODATA; | |
437 | - goto out_file; | |
438 | - } | |
439 | - | |
440 | - /* Skip directories.. */ | |
441 | - if (S_ISDIR(dentry->d_inode->i_mode)) | |
442 | - goto out_file; | |
443 | - | |
444 | - if (!IS_PRIVATE(dentry->d_inode)) { | |
445 | - reiserfs_error(dir->i_sb, "jdm-20003", | |
446 | - "OID %08x [%.*s/%.*s] doesn't have " | |
447 | - "priv flag set [parent is %sset].", | |
448 | - le32_to_cpu(INODE_PKEY(dentry->d_inode)-> | |
449 | - k_objectid), xadir->d_name.len, | |
450 | - xadir->d_name.name, namelen, name, | |
451 | - IS_PRIVATE(xadir->d_inode) ? "" : | |
452 | - "not "); | |
453 | - dput(dentry); | |
454 | - return -EIO; | |
455 | - } | |
456 | - | |
457 | - err = dir->i_op->unlink(dir, dentry); | |
458 | - if (!err) | |
459 | - d_delete(dentry); | |
460 | - | |
461 | - out_file: | |
462 | - dput(dentry); | |
463 | - | |
464 | - out: | |
465 | - return err; | |
466 | -} | |
467 | - | |
468 | -int reiserfs_xattr_del(struct inode *inode, const char *name) | |
469 | -{ | |
470 | - struct dentry *dir; | |
471 | - int err; | |
472 | - | |
473 | - dir = open_xa_dir(inode, FL_READONLY); | |
474 | - if (IS_ERR(dir)) { | |
475 | - err = PTR_ERR(dir); | |
476 | - goto out; | |
477 | - } | |
478 | - | |
479 | - err = __reiserfs_xattr_del(dir, name, strlen(name)); | |
480 | - dput(dir); | |
481 | - | |
482 | - if (!err) { | |
483 | - inode->i_ctime = CURRENT_TIME_SEC; | |
484 | - mark_inode_dirty(inode); | |
485 | - } | |
486 | - | |
487 | - out: | |
488 | - return err; | |
489 | -} | |
490 | - | |
491 | -/* The following are side effects of other operations that aren't explicitly | |
492 | - * modifying extended attributes. This includes operations such as permissions | |
493 | - * or ownership changes, object deletions, etc. */ | |
494 | - | |
495 | -static int | |
496 | -reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, | |
497 | - loff_t offset, u64 ino, unsigned int d_type) | |
498 | -{ | |
499 | - struct dentry *xadir = (struct dentry *)buf; | |
500 | - | |
501 | - return __reiserfs_xattr_del(xadir, name, namelen); | |
502 | - | |
503 | -} | |
504 | - | |
505 | -/* This is called w/ inode->i_mutex downed */ | |
506 | -int reiserfs_delete_xattrs(struct inode *inode) | |
507 | -{ | |
508 | - struct dentry *dir, *root; | |
509 | - int err = 0; | |
510 | - | |
511 | - /* Skip out, an xattr has no xattrs associated with it */ | |
512 | - if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 || | |
513 | - !reiserfs_xattrs(inode->i_sb)) { | |
514 | - return 0; | |
515 | - } | |
516 | - reiserfs_read_lock_xattrs(inode->i_sb); | |
517 | - dir = open_xa_dir(inode, FL_READONLY); | |
518 | - reiserfs_read_unlock_xattrs(inode->i_sb); | |
519 | - if (IS_ERR(dir)) { | |
520 | - err = PTR_ERR(dir); | |
521 | - goto out; | |
522 | - } else if (!dir->d_inode) { | |
523 | - dput(dir); | |
524 | - return 0; | |
525 | - } | |
526 | - | |
527 | - lock_kernel(); | |
528 | - err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); | |
529 | - if (err) { | |
530 | - unlock_kernel(); | |
531 | - goto out_dir; | |
532 | - } | |
533 | - | |
534 | - /* Leftovers besides . and .. -- that's not good. */ | |
535 | - if (dir->d_inode->i_nlink <= 2) { | |
536 | - root = get_xa_root(inode->i_sb, XATTR_REPLACE); | |
537 | - reiserfs_write_lock_xattrs(inode->i_sb); | |
538 | - err = vfs_rmdir(root->d_inode, dir); | |
539 | - reiserfs_write_unlock_xattrs(inode->i_sb); | |
540 | - dput(root); | |
541 | - } else { | |
542 | - reiserfs_warning(inode->i_sb, "jdm-20006", | |
543 | - "Couldn't remove all entries in directory"); | |
544 | - } | |
545 | - unlock_kernel(); | |
546 | - | |
547 | - out_dir: | |
548 | - dput(dir); | |
549 | - | |
550 | - out: | |
551 | - if (!err) | |
552 | - REISERFS_I(inode)->i_flags = | |
553 | - REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; | |
554 | - return err; | |
555 | -} | |
556 | + while (file_pos < isize) { | |
557 | + size_t chunk; | |
558 | + char *data; | |
559 | + size_t skip = 0; | |
560 | + if (isize - file_pos > PAGE_CACHE_SIZE) | |
561 | + chunk = PAGE_CACHE_SIZE; | |
562 | + else | |
563 | + chunk = isize - file_pos; | |
564 | ||
565 | -struct reiserfs_chown_buf { | |
566 | - struct inode *inode; | |
567 | - struct dentry *xadir; | |
568 | - struct iattr *attrs; | |
569 | -}; | |
570 | + page = reiserfs_get_page(dentry->d_inode, file_pos); | |
571 | + if (IS_ERR(page)) { | |
572 | + err = PTR_ERR(page); | |
573 | + goto out_dput; | |
574 | + } | |
575 | ||
576 | -/* XXX: If there is a better way to do this, I'd love to hear about it */ | |
577 | -static int | |
578 | -reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, | |
579 | - loff_t offset, u64 ino, unsigned int d_type) | |
580 | -{ | |
581 | - struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; | |
582 | - struct dentry *xafile, *xadir = chown_buf->xadir; | |
583 | - struct iattr *attrs = chown_buf->attrs; | |
584 | - int err = 0; | |
585 | + lock_page(page); | |
586 | + data = page_address(page); | |
587 | + if (file_pos == 0) { | |
588 | + struct reiserfs_xattr_header *rxh = | |
589 | + (struct reiserfs_xattr_header *)data; | |
590 | + skip = file_pos = sizeof(struct reiserfs_xattr_header); | |
591 | + chunk -= skip; | |
592 | + /* Magic doesn't match up.. */ | |
593 | + if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) { | |
594 | + unlock_page(page); | |
595 | + reiserfs_put_page(page); | |
596 | + reiserfs_warning(inode->i_sb, "jdm-20001", | |
597 | + "Invalid magic for xattr (%s) " | |
598 | + "associated with %k", name, | |
599 | + INODE_PKEY(inode)); | |
600 | + err = -EIO; | |
601 | + goto out_dput; | |
602 | + } | |
603 | + hash = le32_to_cpu(rxh->h_hash); | |
604 | + } | |
605 | + memcpy(buffer + buffer_pos, data + skip, chunk); | |
606 | + unlock_page(page); | |
607 | + reiserfs_put_page(page); | |
608 | + file_pos += chunk; | |
609 | + buffer_pos += chunk; | |
610 | + skip = 0; | |
611 | + } | |
612 | + err = isize - sizeof(struct reiserfs_xattr_header); | |
613 | ||
614 | - xafile = lookup_one_len(name, xadir, namelen); | |
615 | - if (IS_ERR(xafile)) | |
616 | - return PTR_ERR(xafile); | |
617 | - else if (!xafile->d_inode) { | |
618 | - dput(xafile); | |
619 | - return -ENODATA; | |
620 | + if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) != | |
621 | + hash) { | |
622 | + reiserfs_warning(inode->i_sb, "jdm-20002", | |
623 | + "Invalid hash for xattr (%s) associated " | |
624 | + "with %k", name, INODE_PKEY(inode)); | |
625 | + err = -EIO; | |
626 | } | |
627 | ||
628 | - if (!S_ISDIR(xafile->d_inode->i_mode)) | |
629 | - err = notify_change(xafile, attrs); | |
630 | - dput(xafile); | |
631 | +out_dput: | |
632 | + dput(dentry); | |
633 | ||
634 | +out: | |
635 | return err; | |
636 | } | |
637 | ||
638 | -int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) | |
639 | +int reiserfs_xattr_del(struct inode *inode, const char *name) | |
640 | { | |
641 | struct dentry *dir; | |
642 | - int err = 0; | |
643 | - struct reiserfs_chown_buf buf; | |
644 | - unsigned int ia_valid = attrs->ia_valid; | |
645 | + int err; | |
646 | ||
647 | - /* Skip out, an xattr has no xattrs associated with it */ | |
648 | - if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 || | |
649 | - !reiserfs_xattrs(inode->i_sb)) { | |
650 | - return 0; | |
651 | - } | |
652 | - reiserfs_read_lock_xattrs(inode->i_sb); | |
653 | dir = open_xa_dir(inode, FL_READONLY); | |
654 | - reiserfs_read_unlock_xattrs(inode->i_sb); | |
655 | if (IS_ERR(dir)) { | |
656 | - if (PTR_ERR(dir) != -ENODATA) | |
657 | - err = PTR_ERR(dir); | |
658 | - goto out; | |
659 | - } else if (!dir->d_inode) { | |
660 | - dput(dir); | |
661 | + err = PTR_ERR(dir); | |
662 | goto out; | |
663 | } | |
664 | ||
665 | - lock_kernel(); | |
666 | - | |
667 | - attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); | |
668 | - buf.xadir = dir; | |
669 | - buf.attrs = attrs; | |
670 | - buf.inode = inode; | |
671 | + err = __reiserfs_xattr_del(dir, name, strlen(name)); | |
672 | + dput(dir); | |
673 | ||
674 | - err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); | |
675 | - if (err) { | |
676 | - unlock_kernel(); | |
677 | - goto out_dir; | |
678 | + if (!err) { | |
679 | + inode->i_ctime = CURRENT_TIME_SEC; | |
680 | + mark_inode_dirty(inode); | |
681 | } | |
682 | ||
683 | - err = notify_change(dir, attrs); | |
684 | - unlock_kernel(); | |
685 | - | |
686 | - out_dir: | |
687 | - dput(dir); | |
688 | - | |
689 | out: | |
690 | - attrs->ia_valid = ia_valid; | |
691 | return err; | |
692 | } | |
693 | ||
694 | @@ -1101,6 +1100,94 @@ void reiserfs_xattr_unregister_handlers( | |
695 | write_unlock(&handler_lock); | |
696 | } | |
697 | ||
698 | +static int reiserfs_check_acl(struct inode *inode, int mask) | |
699 | +{ | |
700 | + struct posix_acl *acl; | |
701 | + int error = -EAGAIN; /* do regular unix permission checks by default */ | |
702 | + | |
703 | + reiserfs_read_lock_xattr_i(inode); | |
704 | + reiserfs_read_lock_xattrs(inode->i_sb); | |
705 | + | |
706 | + acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); | |
707 | + | |
708 | + reiserfs_read_unlock_xattrs(inode->i_sb); | |
709 | + reiserfs_read_unlock_xattr_i(inode); | |
710 | + | |
711 | + if (acl) { | |
712 | + if (!IS_ERR(acl)) { | |
713 | + error = posix_acl_permission(inode, acl, mask); | |
714 | + posix_acl_release(acl); | |
715 | + } else if (PTR_ERR(acl) != -ENODATA) | |
716 | + error = PTR_ERR(acl); | |
717 | + } | |
718 | + | |
719 | + return error; | |
720 | +} | |
721 | + | |
722 | +int reiserfs_permission(struct inode *inode, int mask) | |
723 | +{ | |
724 | + /* | |
725 | + * We don't do permission checks on the internal objects. | |
726 | + * Permissions are determined by the "owning" object. | |
727 | + */ | |
728 | + if (IS_PRIVATE(inode)) | |
729 | + return 0; | |
730 | + /* | |
731 | + * Stat data v1 doesn't support ACLs. | |
732 | + */ | |
733 | + if (get_inode_sd_version(inode) == STAT_DATA_V1) | |
734 | + return generic_permission(inode, mask, NULL); | |
735 | + else | |
736 | + return generic_permission(inode, mask, reiserfs_check_acl); | |
737 | +} | |
738 | + | |
739 | +static int create_privroot(struct dentry *dentry) | |
740 | +{ | |
741 | + int err; | |
742 | + struct inode *inode = dentry->d_parent->d_inode; | |
743 | + mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR); | |
744 | + err = inode->i_op->mkdir(inode, dentry, 0700); | |
745 | + mutex_unlock(&inode->i_mutex); | |
746 | + if (err) { | |
747 | + dput(dentry); | |
748 | + dentry = NULL; | |
749 | + } | |
750 | + | |
751 | + if (dentry && dentry->d_inode) | |
752 | + reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " | |
753 | + "storage.\n", PRIVROOT_NAME); | |
754 | + | |
755 | + return err; | |
756 | +} | |
757 | + | |
758 | +static int xattr_mount_check(struct super_block *s) | |
759 | +{ | |
760 | + /* We need generation numbers to ensure that the oid mapping is correct | |
761 | + * v3.5 filesystems don't have them. */ | |
762 | + if (!old_format_only(s)) { | |
763 | + set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); | |
764 | + } else if (reiserfs_xattrs_optional(s)) { | |
765 | + /* Old format filesystem, but optional xattrs have been enabled | |
766 | + * at mount time. Error out. */ | |
767 | + reiserfs_warning(s, "jdm-20005", | |
768 | + "xattrs/ACLs not supported on pre v3.6 " | |
769 | + "format filesystem. Failing mount."); | |
770 | + return -EOPNOTSUPP; | |
771 | + } else { | |
772 | + /* Old format filesystem, but no optional xattrs have | |
773 | + * been enabled. This means we silently disable xattrs | |
774 | + * on the filesystem. */ | |
775 | + clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); | |
776 | + } | |
777 | + | |
778 | + return 0; | |
779 | +} | |
780 | + | |
781 | +#else | |
782 | +int __init reiserfs_xattr_register_handlers(void) { return 0; } | |
783 | +void reiserfs_xattr_unregister_handlers(void) {} | |
784 | +#endif | |
785 | + | |
786 | /* This will catch lookups from the fs root to .reiserfs_priv */ | |
787 | static int | |
788 | xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name) | |
789 | @@ -1127,47 +1214,23 @@ int reiserfs_xattr_init(struct super_blo | |
790 | { | |
791 | int err = 0; | |
792 | ||
793 | - /* We need generation numbers to ensure that the oid mapping is correct | |
794 | - * v3.5 filesystems don't have them. */ | |
795 | - if (!old_format_only(s)) { | |
796 | - set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); | |
797 | - } else if (reiserfs_xattrs_optional(s)) { | |
798 | - /* Old format filesystem, but optional xattrs have been enabled | |
799 | - * at mount time. Error out. */ | |
800 | - reiserfs_warning(s, "jdm-20005", | |
801 | - "xattrs/ACLs not supported on pre v3.6 " | |
802 | - "format filesystem. Failing mount."); | |
803 | - err = -EOPNOTSUPP; | |
804 | +#ifdef CONFIG_REISERFS_FS_XATTR | |
805 | + err = xattr_mount_check(s); | |
806 | + if (err) | |
807 | goto error; | |
808 | - } else { | |
809 | - /* Old format filesystem, but no optional xattrs have been enabled. This | |
810 | - * means we silently disable xattrs on the filesystem. */ | |
811 | - clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); | |
812 | - } | |
813 | +#endif | |
814 | ||
815 | /* If we don't have the privroot located yet - go find it */ | |
816 | - if (reiserfs_xattrs(s) && !REISERFS_SB(s)->priv_root) { | |
817 | + if (!REISERFS_SB(s)->priv_root) { | |
818 | struct dentry *dentry; | |
819 | dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, | |
820 | strlen(PRIVROOT_NAME)); | |
821 | if (!IS_ERR(dentry)) { | |
822 | - if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) { | |
823 | - struct inode *inode = dentry->d_parent->d_inode; | |
824 | - mutex_lock_nested(&inode->i_mutex, | |
825 | - I_MUTEX_XATTR); | |
826 | - err = inode->i_op->mkdir(inode, dentry, 0700); | |
827 | - mutex_unlock(&inode->i_mutex); | |
828 | - if (err) { | |
829 | - dput(dentry); | |
830 | - dentry = NULL; | |
831 | - } | |
832 | - | |
833 | - if (dentry && dentry->d_inode) | |
834 | - reiserfs_info(s, "Created %s - " | |
835 | - "reserved for xattr " | |
836 | - "storage.\n", | |
837 | - PRIVROOT_NAME); | |
838 | - } else if (!dentry->d_inode) { | |
839 | +#ifdef CONFIG_REISERFS_FS_XATTR | |
840 | + if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) | |
841 | + err = create_privroot(dentry); | |
842 | +#endif | |
843 | + if (!dentry->d_inode) { | |
844 | dput(dentry); | |
845 | dentry = NULL; | |
846 | } | |
847 | @@ -1178,73 +1241,37 @@ int reiserfs_xattr_init(struct super_blo | |
848 | s->s_root->d_op = &xattr_lookup_poison_ops; | |
849 | dentry->d_inode->i_flags |= S_PRIVATE; | |
850 | REISERFS_SB(s)->priv_root = dentry; | |
851 | - } else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */ | |
852 | - /* If we're read-only it just means that the dir hasn't been | |
853 | - * created. Not an error -- just no xattrs on the fs. We'll | |
854 | - * check again if we go read-write */ | |
855 | +#ifdef CONFIG_REISERFS_FS_XATTR | |
856 | + /* xattrs are unavailable */ | |
857 | + } else if (!(mount_flags & MS_RDONLY)) { | |
858 | + /* If we're read-only it just means that the dir | |
859 | + * hasn't been created. Not an error -- just no | |
860 | + * xattrs on the fs. We'll check again if we | |
861 | + * go read-write */ | |
862 | reiserfs_warning(s, "jdm-20006", | |
863 | "xattrs/ACLs enabled and couldn't " | |
864 | "find/create .reiserfs_priv. " | |
865 | "Failing mount."); | |
866 | err = -EOPNOTSUPP; | |
867 | +#endif | |
868 | } | |
869 | } | |
870 | ||
871 | - error: | |
872 | - /* This is only nonzero if there was an error initializing the xattr | |
873 | - * directory or if there is a condition where we don't support them. */ | |
874 | +#ifdef CONFIG_REISERFS_FS_XATTR | |
875 | +error: | |
876 | if (err) { | |
877 | clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); | |
878 | clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt)); | |
879 | clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt)); | |
880 | } | |
881 | +#endif | |
882 | ||
883 | /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */ | |
884 | s->s_flags = s->s_flags & ~MS_POSIXACL; | |
885 | +#ifdef CONFIG_REISERFS_FS_POSIX_ACL | |
886 | if (reiserfs_posixacl(s)) | |
887 | s->s_flags |= MS_POSIXACL; | |
888 | +#endif | |
889 | ||
890 | return err; | |
891 | } | |
892 | - | |
893 | -static int reiserfs_check_acl(struct inode *inode, int mask) | |
894 | -{ | |
895 | - struct posix_acl *acl; | |
896 | - int error = -EAGAIN; /* do regular unix permission checks by default */ | |
897 | - | |
898 | - reiserfs_read_lock_xattr_i(inode); | |
899 | - reiserfs_read_lock_xattrs(inode->i_sb); | |
900 | - | |
901 | - acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); | |
902 | - | |
903 | - reiserfs_read_unlock_xattrs(inode->i_sb); | |
904 | - reiserfs_read_unlock_xattr_i(inode); | |
905 | - | |
906 | - if (acl) { | |
907 | - if (!IS_ERR(acl)) { | |
908 | - error = posix_acl_permission(inode, acl, mask); | |
909 | - posix_acl_release(acl); | |
910 | - } else if (PTR_ERR(acl) != -ENODATA) | |
911 | - error = PTR_ERR(acl); | |
912 | - } | |
913 | - | |
914 | - return error; | |
915 | -} | |
916 | - | |
917 | -int reiserfs_permission(struct inode *inode, int mask) | |
918 | -{ | |
919 | - /* | |
920 | - * We don't do permission checks on the internal objects. | |
921 | - * Permissions are determined by the "owning" object. | |
922 | - */ | |
923 | - if (IS_PRIVATE(inode)) | |
924 | - return 0; | |
925 | - | |
926 | - /* | |
927 | - * Stat data v1 doesn't support ACLs. | |
928 | - */ | |
929 | - if (get_inode_sd_version(inode) == STAT_DATA_V1) | |
930 | - return generic_permission(inode, mask, NULL); | |
931 | - else | |
932 | - return generic_permission(inode, mask, reiserfs_check_acl); | |
933 | -} | |
934 | --- a/include/linux/reiserfs_fs_sb.h | |
935 | +++ b/include/linux/reiserfs_fs_sb.h | |
936 | @@ -401,8 +401,8 @@ struct reiserfs_sb_info { | |
937 | int reserved_blocks; /* amount of blocks reserved for further allocations */ | |
938 | spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */ | |
939 | struct dentry *priv_root; /* root of /.reiserfs_priv */ | |
940 | -#ifdef CONFIG_REISERFS_FS_XATTR | |
941 | struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */ | |
942 | +#ifdef CONFIG_REISERFS_FS_XATTR | |
943 | struct rw_semaphore xattr_dir_sem; | |
944 | #endif | |
945 | int j_errno; | |
946 | --- a/include/linux/reiserfs_xattr.h | |
947 | +++ b/include/linux/reiserfs_xattr.h | |
948 | @@ -43,6 +43,12 @@ struct reiserfs_xattr_handler { | |
949 | struct list_head handlers; | |
950 | }; | |
951 | ||
952 | +int reiserfs_xattr_register_handlers(void) __init; | |
953 | +void reiserfs_xattr_unregister_handlers(void); | |
954 | +int reiserfs_xattr_init(struct super_block *sb, int mount_flags); | |
955 | +int reiserfs_delete_xattrs(struct inode *inode); | |
956 | +int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); | |
957 | + | |
958 | #ifdef CONFIG_REISERFS_FS_XATTR | |
959 | #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) | |
960 | ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name, | |
961 | @@ -51,9 +57,6 @@ int reiserfs_setxattr(struct dentry *den | |
962 | const void *value, size_t size, int flags); | |
963 | ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size); | |
964 | int reiserfs_removexattr(struct dentry *dentry, const char *name); | |
965 | -int reiserfs_delete_xattrs(struct inode *inode); | |
966 | -int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); | |
967 | -int reiserfs_xattr_init(struct super_block *sb, int mount_flags); | |
968 | int reiserfs_permission(struct inode *inode, int mask); | |
969 | ||
970 | int reiserfs_xattr_del(struct inode *, const char *); | |
971 | @@ -64,9 +67,6 @@ extern struct reiserfs_xattr_handler use | |
972 | extern struct reiserfs_xattr_handler trusted_handler; | |
973 | extern struct reiserfs_xattr_handler security_handler; | |
974 | ||
975 | -int reiserfs_xattr_register_handlers(void) __init; | |
976 | -void reiserfs_xattr_unregister_handlers(void); | |
977 | - | |
978 | static inline void reiserfs_write_lock_xattrs(struct super_block *sb) | |
979 | { | |
980 | down_write(&REISERFS_XATTR_DIR_SEM(sb)); | |
981 | @@ -121,23 +121,6 @@ static inline void reiserfs_init_xattr_r | |
982 | ||
983 | #define reiserfs_permission NULL | |
984 | ||
985 | -#define reiserfs_xattr_register_handlers() 0 | |
986 | -#define reiserfs_xattr_unregister_handlers() | |
987 | - | |
988 | -static inline int reiserfs_delete_xattrs(struct inode *inode) | |
989 | -{ | |
990 | - return 0; | |
991 | -}; | |
992 | -static inline int reiserfs_chown_xattrs(struct inode *inode, | |
993 | - struct iattr *attrs) | |
994 | -{ | |
995 | - return 0; | |
996 | -}; | |
997 | -static inline int reiserfs_xattr_init(struct super_block *sb, int mount_flags) | |
998 | -{ | |
999 | - sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */ | |
1000 | - return 0; | |
1001 | -}; | |
1002 | static inline void reiserfs_init_xattr_rwsem(struct inode *inode) | |
1003 | { | |
1004 | } |