diff options
Diffstat (limited to 'fs/reiserfs/xattr.c')
-rw-r--r-- | fs/reiserfs/xattr.c | 402 |
1 files changed, 115 insertions, 287 deletions
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index c2e3a92aaf2b..1baafec64331 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c | |||
@@ -167,218 +167,65 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags) | |||
167 | 167 | ||
168 | } | 168 | } |
169 | 169 | ||
170 | /* | ||
171 | * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but | ||
172 | * we need to drop the path before calling the filldir struct. That | ||
173 | * would be a big performance hit to the non-xattr case, so I've copied | ||
174 | * the whole thing for now. --clm | ||
175 | * | ||
176 | * the big difference is that I go backwards through the directory, | ||
177 | * and don't mess with f->f_pos, but the idea is the same. Do some | ||
178 | * action on each and every entry in the directory. | ||
179 | * | ||
180 | * we're called with i_mutex held, so there are no worries about the directory | ||
181 | * changing underneath us. | ||
182 | */ | ||
183 | static int __xattr_readdir(struct inode *inode, void *dirent, filldir_t filldir) | ||
184 | { | ||
185 | struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */ | ||
186 | INITIALIZE_PATH(path_to_entry); | ||
187 | struct buffer_head *bh; | ||
188 | int entry_num; | ||
189 | struct item_head *ih, tmp_ih; | ||
190 | int search_res; | ||
191 | char *local_buf; | ||
192 | loff_t next_pos; | ||
193 | char small_buf[32]; /* avoid kmalloc if we can */ | ||
194 | struct reiserfs_de_head *deh; | ||
195 | int d_reclen; | ||
196 | char *d_name; | ||
197 | off_t d_off; | ||
198 | ino_t d_ino; | ||
199 | struct reiserfs_dir_entry de; | ||
200 | |||
201 | /* form key for search the next directory entry using f_pos field of | ||
202 | file structure */ | ||
203 | next_pos = max_reiserfs_offset(inode); | ||
204 | |||
205 | while (1) { | ||
206 | research: | ||
207 | if (next_pos <= DOT_DOT_OFFSET) | ||
208 | break; | ||
209 | make_cpu_key(&pos_key, inode, next_pos, TYPE_DIRENTRY, 3); | ||
210 | |||
211 | search_res = | ||
212 | search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry, | ||
213 | &de); | ||
214 | if (search_res == IO_ERROR) { | ||
215 | // FIXME: we could just skip part of directory which could | ||
216 | // not be read | ||
217 | pathrelse(&path_to_entry); | ||
218 | return -EIO; | ||
219 | } | ||
220 | |||
221 | if (search_res == NAME_NOT_FOUND) | ||
222 | de.de_entry_num--; | ||
223 | |||
224 | set_de_name_and_namelen(&de); | ||
225 | entry_num = de.de_entry_num; | ||
226 | deh = &(de.de_deh[entry_num]); | ||
227 | |||
228 | bh = de.de_bh; | ||
229 | ih = de.de_ih; | ||
230 | |||
231 | if (!is_direntry_le_ih(ih)) { | ||
232 | reiserfs_error(inode->i_sb, "jdm-20000", | ||
233 | "not direntry %h", ih); | ||
234 | break; | ||
235 | } | ||
236 | copy_item_head(&tmp_ih, ih); | ||
237 | |||
238 | /* we must have found item, that is item of this directory, */ | ||
239 | RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key), | ||
240 | "vs-9000: found item %h does not match to dir we readdir %K", | ||
241 | ih, &pos_key); | ||
242 | |||
243 | if (deh_offset(deh) <= DOT_DOT_OFFSET) { | ||
244 | break; | ||
245 | } | ||
246 | |||
247 | /* look for the previous entry in the directory */ | ||
248 | next_pos = deh_offset(deh) - 1; | ||
249 | |||
250 | if (!de_visible(deh)) | ||
251 | /* it is hidden entry */ | ||
252 | continue; | ||
253 | |||
254 | d_reclen = entry_length(bh, ih, entry_num); | ||
255 | d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh); | ||
256 | d_off = deh_offset(deh); | ||
257 | d_ino = deh_objectid(deh); | ||
258 | |||
259 | if (!d_name[d_reclen - 1]) | ||
260 | d_reclen = strlen(d_name); | ||
261 | |||
262 | if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)) { | ||
263 | /* too big to send back to VFS */ | ||
264 | continue; | ||
265 | } | ||
266 | |||
267 | /* Ignore the .reiserfs_priv entry */ | ||
268 | if (reiserfs_xattrs(inode->i_sb) && | ||
269 | !old_format_only(inode->i_sb) && | ||
270 | deh_objectid(deh) == | ||
271 | le32_to_cpu(INODE_PKEY | ||
272 | (REISERFS_SB(inode->i_sb)->priv_root->d_inode)-> | ||
273 | k_objectid)) | ||
274 | continue; | ||
275 | |||
276 | if (d_reclen <= 32) { | ||
277 | local_buf = small_buf; | ||
278 | } else { | ||
279 | local_buf = kmalloc(d_reclen, GFP_NOFS); | ||
280 | if (!local_buf) { | ||
281 | pathrelse(&path_to_entry); | ||
282 | return -ENOMEM; | ||
283 | } | ||
284 | if (item_moved(&tmp_ih, &path_to_entry)) { | ||
285 | kfree(local_buf); | ||
286 | |||
287 | /* sigh, must retry. Do this same offset again */ | ||
288 | next_pos = d_off; | ||
289 | goto research; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | // Note, that we copy name to user space via temporary | ||
294 | // buffer (local_buf) because filldir will block if | ||
295 | // user space buffer is swapped out. At that time | ||
296 | // entry can move to somewhere else | ||
297 | memcpy(local_buf, d_name, d_reclen); | ||
298 | |||
299 | /* the filldir function might need to start transactions, | ||
300 | * or do who knows what. Release the path now that we've | ||
301 | * copied all the important stuff out of the deh | ||
302 | */ | ||
303 | pathrelse(&path_to_entry); | ||
304 | |||
305 | if (filldir(dirent, local_buf, d_reclen, d_off, d_ino, | ||
306 | DT_UNKNOWN) < 0) { | ||
307 | if (local_buf != small_buf) { | ||
308 | kfree(local_buf); | ||
309 | } | ||
310 | goto end; | ||
311 | } | ||
312 | if (local_buf != small_buf) { | ||
313 | kfree(local_buf); | ||
314 | } | ||
315 | } /* while */ | ||
316 | |||
317 | end: | ||
318 | pathrelse(&path_to_entry); | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * this could be done with dedicated readdir ops for the xattr files, | ||
324 | * but I want to get something working asap | ||
325 | * this is stolen from vfs_readdir | ||
326 | * | ||
327 | */ | ||
328 | static | ||
329 | int xattr_readdir(struct inode *inode, filldir_t filler, void *buf) | ||
330 | { | ||
331 | int res = -ENOENT; | ||
332 | if (!IS_DEADDIR(inode)) { | ||
333 | lock_kernel(); | ||
334 | res = __xattr_readdir(inode, buf, filler); | ||
335 | unlock_kernel(); | ||
336 | } | ||
337 | return res; | ||
338 | } | ||
339 | |||
340 | /* The following are side effects of other operations that aren't explicitly | 170 | /* The following are side effects of other operations that aren't explicitly |
341 | * modifying extended attributes. This includes operations such as permissions | 171 | * modifying extended attributes. This includes operations such as permissions |
342 | * or ownership changes, object deletions, etc. */ | 172 | * or ownership changes, object deletions, etc. */ |
173 | struct reiserfs_dentry_buf { | ||
174 | struct dentry *xadir; | ||
175 | int count; | ||
176 | struct dentry *dentries[8]; | ||
177 | }; | ||
343 | 178 | ||
344 | static int | 179 | static int |
345 | reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, | 180 | fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset, |
346 | loff_t offset, u64 ino, unsigned int d_type) | 181 | u64 ino, unsigned int d_type) |
347 | { | 182 | { |
348 | struct dentry *xadir = (struct dentry *)buf; | 183 | struct reiserfs_dentry_buf *dbuf = buf; |
349 | struct dentry *dentry; | 184 | struct dentry *dentry; |
350 | int err = 0; | ||
351 | 185 | ||
352 | dentry = lookup_one_len(name, xadir, namelen); | 186 | if (dbuf->count == ARRAY_SIZE(dbuf->dentries)) |
187 | return -ENOSPC; | ||
188 | |||
189 | if (name[0] == '.' && (name[1] == '\0' || | ||
190 | (name[1] == '.' && name[2] == '\0'))) | ||
191 | return 0; | ||
192 | |||
193 | dentry = lookup_one_len(name, dbuf->xadir, namelen); | ||
353 | if (IS_ERR(dentry)) { | 194 | if (IS_ERR(dentry)) { |
354 | err = PTR_ERR(dentry); | 195 | return PTR_ERR(dentry); |
355 | goto out; | ||
356 | } else if (!dentry->d_inode) { | 196 | } else if (!dentry->d_inode) { |
357 | err = -ENODATA; | 197 | /* A directory entry exists, but no file? */ |
358 | goto out_file; | 198 | reiserfs_error(dentry->d_sb, "xattr-20003", |
199 | "Corrupted directory: xattr %s listed but " | ||
200 | "not found for file %s.\n", | ||
201 | dentry->d_name.name, dbuf->xadir->d_name.name); | ||
202 | dput(dentry); | ||
203 | return -EIO; | ||
359 | } | 204 | } |
360 | 205 | ||
361 | /* Skip directories.. */ | 206 | dbuf->dentries[dbuf->count++] = dentry; |
362 | if (S_ISDIR(dentry->d_inode->i_mode)) | 207 | return 0; |
363 | goto out_file; | 208 | } |
364 | |||
365 | err = xattr_unlink(xadir->d_inode, dentry); | ||
366 | |||
367 | out_file: | ||
368 | dput(dentry); | ||
369 | 209 | ||
370 | out: | 210 | static void |
371 | return err; | 211 | cleanup_dentry_buf(struct reiserfs_dentry_buf *buf) |
212 | { | ||
213 | int i; | ||
214 | for (i = 0; i < buf->count; i++) | ||
215 | if (buf->dentries[i]) | ||
216 | dput(buf->dentries[i]); | ||
372 | } | 217 | } |
373 | 218 | ||
374 | /* This is called w/ inode->i_mutex downed */ | 219 | static int reiserfs_for_each_xattr(struct inode *inode, |
375 | int reiserfs_delete_xattrs(struct inode *inode) | 220 | int (*action)(struct dentry *, void *), |
221 | void *data) | ||
376 | { | 222 | { |
377 | int err = -ENODATA; | 223 | struct dentry *dir; |
378 | struct dentry *dir, *root; | 224 | int i, err = 0; |
379 | struct reiserfs_transaction_handle th; | 225 | loff_t pos = 0; |
380 | int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + | 226 | struct reiserfs_dentry_buf buf = { |
381 | 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); | 227 | .count = 0, |
228 | }; | ||
382 | 229 | ||
383 | /* Skip out, an xattr has no xattrs associated with it */ | 230 | /* Skip out, an xattr has no xattrs associated with it */ |
384 | if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) | 231 | if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) |
@@ -389,117 +236,97 @@ int reiserfs_delete_xattrs(struct inode *inode) | |||
389 | err = PTR_ERR(dir); | 236 | err = PTR_ERR(dir); |
390 | goto out; | 237 | goto out; |
391 | } else if (!dir->d_inode) { | 238 | } else if (!dir->d_inode) { |
392 | dput(dir); | 239 | err = 0; |
393 | goto out; | 240 | goto out_dir; |
394 | } | 241 | } |
395 | 242 | ||
396 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); | 243 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); |
397 | err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); | 244 | buf.xadir = dir; |
398 | mutex_unlock(&dir->d_inode->i_mutex); | 245 | err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos); |
399 | if (err) { | 246 | while ((err == 0 || err == -ENOSPC) && buf.count) { |
400 | dput(dir); | 247 | err = 0; |
401 | goto out; | 248 | |
249 | for (i = 0; i < buf.count && buf.dentries[i]; i++) { | ||
250 | int lerr = 0; | ||
251 | struct dentry *dentry = buf.dentries[i]; | ||
252 | |||
253 | if (err == 0 && !S_ISDIR(dentry->d_inode->i_mode)) | ||
254 | lerr = action(dentry, data); | ||
255 | |||
256 | dput(dentry); | ||
257 | buf.dentries[i] = NULL; | ||
258 | err = lerr ?: err; | ||
259 | } | ||
260 | buf.count = 0; | ||
261 | if (!err) | ||
262 | err = reiserfs_readdir_dentry(dir, &buf, | ||
263 | fill_with_dentries, &pos); | ||
402 | } | 264 | } |
265 | mutex_unlock(&dir->d_inode->i_mutex); | ||
403 | 266 | ||
404 | root = dget(dir->d_parent); | 267 | /* Clean up after a failed readdir */ |
405 | dput(dir); | 268 | cleanup_dentry_buf(&buf); |
406 | 269 | ||
407 | /* We start a transaction here to avoid a ABBA situation | ||
408 | * between the xattr root's i_mutex and the journal lock. | ||
409 | * Inode creation will inherit an ACL, which requires a | ||
410 | * lookup. The lookup locks the xattr root i_mutex with a | ||
411 | * transaction open. Inode deletion takes teh xattr root | ||
412 | * i_mutex to delete the directory and then starts a | ||
413 | * transaction inside it. Boom. This doesn't incur much | ||
414 | * additional overhead since the reiserfs_rmdir transaction | ||
415 | * will just nest inside the outer transaction. */ | ||
416 | err = journal_begin(&th, inode->i_sb, blocks); | ||
417 | if (!err) { | 270 | if (!err) { |
418 | int jerror; | 271 | /* We start a transaction here to avoid a ABBA situation |
419 | mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_XATTR); | 272 | * between the xattr root's i_mutex and the journal lock. |
420 | err = xattr_rmdir(root->d_inode, dir); | 273 | * This doesn't incur much additional overhead since the |
421 | jerror = journal_end(&th, inode->i_sb, blocks); | 274 | * new transaction will just nest inside the |
422 | mutex_unlock(&root->d_inode->i_mutex); | 275 | * outer transaction. */ |
423 | err = jerror ?: err; | 276 | int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + |
277 | 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); | ||
278 | struct reiserfs_transaction_handle th; | ||
279 | err = journal_begin(&th, inode->i_sb, blocks); | ||
280 | if (!err) { | ||
281 | int jerror; | ||
282 | mutex_lock_nested(&dir->d_parent->d_inode->i_mutex, | ||
283 | I_MUTEX_XATTR); | ||
284 | err = action(dir, data); | ||
285 | jerror = journal_end(&th, inode->i_sb, blocks); | ||
286 | mutex_unlock(&dir->d_parent->d_inode->i_mutex); | ||
287 | err = jerror ?: err; | ||
288 | } | ||
424 | } | 289 | } |
425 | 290 | out_dir: | |
426 | dput(root); | 291 | dput(dir); |
427 | out: | 292 | out: |
428 | if (err) | 293 | /* -ENODATA isn't an error */ |
429 | reiserfs_warning(inode->i_sb, "jdm-20004", | 294 | if (err == -ENODATA) |
430 | "Couldn't remove all xattrs (%d)\n", err); | 295 | err = 0; |
431 | return err; | 296 | return err; |
432 | } | 297 | } |
433 | 298 | ||
434 | struct reiserfs_chown_buf { | 299 | static int delete_one_xattr(struct dentry *dentry, void *data) |
435 | struct inode *inode; | ||
436 | struct dentry *xadir; | ||
437 | struct iattr *attrs; | ||
438 | }; | ||
439 | |||
440 | /* XXX: If there is a better way to do this, I'd love to hear about it */ | ||
441 | static int | ||
442 | reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, | ||
443 | loff_t offset, u64 ino, unsigned int d_type) | ||
444 | { | 300 | { |
445 | struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; | 301 | struct inode *dir = dentry->d_parent->d_inode; |
446 | struct dentry *xafile, *xadir = chown_buf->xadir; | ||
447 | struct iattr *attrs = chown_buf->attrs; | ||
448 | int err = 0; | ||
449 | 302 | ||
450 | xafile = lookup_one_len(name, xadir, namelen); | 303 | /* This is the xattr dir, handle specially. */ |
451 | if (IS_ERR(xafile)) | 304 | if (S_ISDIR(dentry->d_inode->i_mode)) |
452 | return PTR_ERR(xafile); | 305 | return xattr_rmdir(dir, dentry); |
453 | else if (!xafile->d_inode) { | ||
454 | dput(xafile); | ||
455 | return -ENODATA; | ||
456 | } | ||
457 | 306 | ||
458 | if (!S_ISDIR(xafile->d_inode->i_mode)) { | 307 | return xattr_unlink(dir, dentry); |
459 | mutex_lock_nested(&xafile->d_inode->i_mutex, I_MUTEX_CHILD); | 308 | } |
460 | err = reiserfs_setattr(xafile, attrs); | 309 | |
461 | mutex_unlock(&xafile->d_inode->i_mutex); | 310 | static int chown_one_xattr(struct dentry *dentry, void *data) |
462 | } | 311 | { |
463 | dput(xafile); | 312 | struct iattr *attrs = data; |
313 | return reiserfs_setattr(dentry, attrs); | ||
314 | } | ||
464 | 315 | ||
316 | /* No i_mutex, but the inode is unconnected. */ | ||
317 | int reiserfs_delete_xattrs(struct inode *inode) | ||
318 | { | ||
319 | int err = reiserfs_for_each_xattr(inode, delete_one_xattr, NULL); | ||
320 | if (err) | ||
321 | reiserfs_warning(inode->i_sb, "jdm-20004", | ||
322 | "Couldn't delete all xattrs (%d)\n", err); | ||
465 | return err; | 323 | return err; |
466 | } | 324 | } |
467 | 325 | ||
326 | /* inode->i_mutex: down */ | ||
468 | int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) | 327 | int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) |
469 | { | 328 | { |
470 | struct dentry *dir; | 329 | int err = reiserfs_for_each_xattr(inode, chown_one_xattr, attrs); |
471 | int err = 0; | ||
472 | struct reiserfs_chown_buf buf; | ||
473 | unsigned int ia_valid = attrs->ia_valid; | ||
474 | |||
475 | /* Skip out, an xattr has no xattrs associated with it */ | ||
476 | if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) | ||
477 | return 0; | ||
478 | |||
479 | dir = open_xa_dir(inode, XATTR_REPLACE); | ||
480 | if (IS_ERR(dir)) { | ||
481 | if (PTR_ERR(dir) != -ENODATA) | ||
482 | err = PTR_ERR(dir); | ||
483 | goto out; | ||
484 | } else if (!dir->d_inode) | ||
485 | goto out_dir; | ||
486 | |||
487 | attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); | ||
488 | buf.xadir = dir; | ||
489 | buf.attrs = attrs; | ||
490 | buf.inode = inode; | ||
491 | |||
492 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); | ||
493 | err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); | ||
494 | |||
495 | if (!err) | ||
496 | err = reiserfs_setattr(dir, attrs); | ||
497 | mutex_unlock(&dir->d_inode->i_mutex); | ||
498 | |||
499 | attrs->ia_valid = ia_valid; | ||
500 | out_dir: | ||
501 | dput(dir); | ||
502 | out: | ||
503 | if (err) | 330 | if (err) |
504 | reiserfs_warning(inode->i_sb, "jdm-20007", | 331 | reiserfs_warning(inode->i_sb, "jdm-20007", |
505 | "Couldn't chown all xattrs (%d)\n", err); | 332 | "Couldn't chown all xattrs (%d)\n", err); |
@@ -1004,6 +831,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) | |||
1004 | { | 831 | { |
1005 | struct dentry *dir; | 832 | struct dentry *dir; |
1006 | int err = 0; | 833 | int err = 0; |
834 | loff_t pos = 0; | ||
1007 | struct listxattr_buf buf = { | 835 | struct listxattr_buf buf = { |
1008 | .inode = dentry->d_inode, | 836 | .inode = dentry->d_inode, |
1009 | .buf = buffer, | 837 | .buf = buffer, |
@@ -1026,7 +854,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) | |||
1026 | } | 854 | } |
1027 | 855 | ||
1028 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); | 856 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); |
1029 | err = xattr_readdir(dir->d_inode, listxattr_filler, &buf); | 857 | err = reiserfs_readdir_dentry(dir, &buf, listxattr_filler, &pos); |
1030 | mutex_unlock(&dir->d_inode->i_mutex); | 858 | mutex_unlock(&dir->d_inode->i_mutex); |
1031 | 859 | ||
1032 | if (!err) | 860 | if (!err) |