diff options
| -rw-r--r-- | fs/ocfs2/namei.c | 107 | ||||
| -rw-r--r-- | fs/ocfs2/xattr.c | 70 | ||||
| -rw-r--r-- | fs/ocfs2/xattr.h | 17 |
3 files changed, 182 insertions, 12 deletions
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index e8ff0bae179d..40da46b907fb 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
| @@ -229,6 +229,12 @@ static int ocfs2_mknod(struct inode *dir, | |||
| 229 | struct inode *inode = NULL; | 229 | struct inode *inode = NULL; |
| 230 | struct ocfs2_alloc_context *inode_ac = NULL; | 230 | struct ocfs2_alloc_context *inode_ac = NULL; |
| 231 | struct ocfs2_alloc_context *data_ac = NULL; | 231 | struct ocfs2_alloc_context *data_ac = NULL; |
| 232 | struct ocfs2_alloc_context *xattr_ac = NULL; | ||
| 233 | int want_clusters = 0; | ||
| 234 | int xattr_credits = 0; | ||
| 235 | struct ocfs2_security_xattr_info si = { | ||
| 236 | .enable = 1, | ||
| 237 | }; | ||
| 232 | 238 | ||
| 233 | mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode, | 239 | mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode, |
| 234 | (unsigned long)dev, dentry->d_name.len, | 240 | (unsigned long)dev, dentry->d_name.len, |
| @@ -285,17 +291,39 @@ static int ocfs2_mknod(struct inode *dir, | |||
| 285 | goto leave; | 291 | goto leave; |
| 286 | } | 292 | } |
| 287 | 293 | ||
| 288 | /* Reserve a cluster if creating an extent based directory. */ | 294 | /* get security xattr */ |
| 289 | if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) { | 295 | status = ocfs2_init_security_get(inode, dir, &si); |
| 290 | status = ocfs2_reserve_clusters(osb, 1, &data_ac); | 296 | if (status) { |
| 297 | if (status == -EOPNOTSUPP) | ||
| 298 | si.enable = 0; | ||
| 299 | else { | ||
| 300 | mlog_errno(status); | ||
| 301 | goto leave; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | /* calculate meta data/clusters for setting security xattr */ | ||
| 306 | if (si.enable) { | ||
| 307 | status = ocfs2_calc_security_init(dir, &si, &want_clusters, | ||
| 308 | &xattr_credits, &xattr_ac); | ||
| 291 | if (status < 0) { | 309 | if (status < 0) { |
| 292 | if (status != -ENOSPC) | 310 | mlog_errno(status); |
| 293 | mlog_errno(status); | ||
| 294 | goto leave; | 311 | goto leave; |
| 295 | } | 312 | } |
| 296 | } | 313 | } |
| 297 | 314 | ||
| 298 | handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS); | 315 | /* Reserve a cluster if creating an extent based directory. */ |
| 316 | if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) | ||
| 317 | want_clusters += 1; | ||
| 318 | |||
| 319 | status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac); | ||
| 320 | if (status < 0) { | ||
| 321 | if (status != -ENOSPC) | ||
| 322 | mlog_errno(status); | ||
| 323 | goto leave; | ||
| 324 | } | ||
| 325 | |||
| 326 | handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS + xattr_credits); | ||
| 299 | if (IS_ERR(handle)) { | 327 | if (IS_ERR(handle)) { |
| 300 | status = PTR_ERR(handle); | 328 | status = PTR_ERR(handle); |
| 301 | handle = NULL; | 329 | handle = NULL; |
| @@ -335,6 +363,15 @@ static int ocfs2_mknod(struct inode *dir, | |||
| 335 | inc_nlink(dir); | 363 | inc_nlink(dir); |
| 336 | } | 364 | } |
| 337 | 365 | ||
| 366 | if (si.enable) { | ||
| 367 | status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si, | ||
| 368 | xattr_ac, data_ac); | ||
| 369 | if (status < 0) { | ||
| 370 | mlog_errno(status); | ||
| 371 | goto leave; | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 338 | status = ocfs2_add_entry(handle, dentry, inode, | 375 | status = ocfs2_add_entry(handle, dentry, inode, |
| 339 | OCFS2_I(inode)->ip_blkno, parent_fe_bh, | 376 | OCFS2_I(inode)->ip_blkno, parent_fe_bh, |
| 340 | de_bh); | 377 | de_bh); |
| @@ -366,6 +403,8 @@ leave: | |||
| 366 | brelse(new_fe_bh); | 403 | brelse(new_fe_bh); |
| 367 | brelse(de_bh); | 404 | brelse(de_bh); |
| 368 | brelse(parent_fe_bh); | 405 | brelse(parent_fe_bh); |
| 406 | kfree(si.name); | ||
| 407 | kfree(si.value); | ||
| 369 | 408 | ||
| 370 | if ((status < 0) && inode) { | 409 | if ((status < 0) && inode) { |
| 371 | clear_nlink(inode); | 410 | clear_nlink(inode); |
| @@ -378,6 +417,9 @@ leave: | |||
| 378 | if (data_ac) | 417 | if (data_ac) |
| 379 | ocfs2_free_alloc_context(data_ac); | 418 | ocfs2_free_alloc_context(data_ac); |
| 380 | 419 | ||
| 420 | if (xattr_ac) | ||
| 421 | ocfs2_free_alloc_context(xattr_ac); | ||
| 422 | |||
| 381 | mlog_exit(status); | 423 | mlog_exit(status); |
| 382 | 424 | ||
| 383 | return status; | 425 | return status; |
| @@ -1508,6 +1550,12 @@ static int ocfs2_symlink(struct inode *dir, | |||
| 1508 | handle_t *handle = NULL; | 1550 | handle_t *handle = NULL; |
| 1509 | struct ocfs2_alloc_context *inode_ac = NULL; | 1551 | struct ocfs2_alloc_context *inode_ac = NULL; |
| 1510 | struct ocfs2_alloc_context *data_ac = NULL; | 1552 | struct ocfs2_alloc_context *data_ac = NULL; |
| 1553 | struct ocfs2_alloc_context *xattr_ac = NULL; | ||
| 1554 | int want_clusters = 0; | ||
| 1555 | int xattr_credits = 0; | ||
| 1556 | struct ocfs2_security_xattr_info si = { | ||
| 1557 | .enable = 1, | ||
| 1558 | }; | ||
| 1511 | 1559 | ||
| 1512 | mlog_entry("(0x%p, 0x%p, symname='%s' actual='%.*s')\n", dir, | 1560 | mlog_entry("(0x%p, 0x%p, symname='%s' actual='%.*s')\n", dir, |
| 1513 | dentry, symname, dentry->d_name.len, dentry->d_name.name); | 1561 | dentry, symname, dentry->d_name.len, dentry->d_name.name); |
| @@ -1561,17 +1609,39 @@ static int ocfs2_symlink(struct inode *dir, | |||
| 1561 | goto bail; | 1609 | goto bail; |
| 1562 | } | 1610 | } |
| 1563 | 1611 | ||
| 1564 | /* don't reserve bitmap space for fast symlinks. */ | 1612 | /* get security xattr */ |
| 1565 | if (l > ocfs2_fast_symlink_chars(sb)) { | 1613 | status = ocfs2_init_security_get(inode, dir, &si); |
| 1566 | status = ocfs2_reserve_clusters(osb, 1, &data_ac); | 1614 | if (status) { |
| 1615 | if (status == -EOPNOTSUPP) | ||
| 1616 | si.enable = 0; | ||
| 1617 | else { | ||
| 1618 | mlog_errno(status); | ||
| 1619 | goto bail; | ||
| 1620 | } | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | /* calculate meta data/clusters for setting security xattr */ | ||
| 1624 | if (si.enable) { | ||
| 1625 | status = ocfs2_calc_security_init(dir, &si, &want_clusters, | ||
| 1626 | &xattr_credits, &xattr_ac); | ||
| 1567 | if (status < 0) { | 1627 | if (status < 0) { |
| 1568 | if (status != -ENOSPC) | 1628 | mlog_errno(status); |
| 1569 | mlog_errno(status); | ||
| 1570 | goto bail; | 1629 | goto bail; |
| 1571 | } | 1630 | } |
| 1572 | } | 1631 | } |
| 1573 | 1632 | ||
| 1574 | handle = ocfs2_start_trans(osb, credits); | 1633 | /* don't reserve bitmap space for fast symlinks. */ |
| 1634 | if (l > ocfs2_fast_symlink_chars(sb)) | ||
| 1635 | want_clusters += 1; | ||
| 1636 | |||
| 1637 | status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac); | ||
| 1638 | if (status < 0) { | ||
| 1639 | if (status != -ENOSPC) | ||
| 1640 | mlog_errno(status); | ||
| 1641 | goto bail; | ||
| 1642 | } | ||
| 1643 | |||
| 1644 | handle = ocfs2_start_trans(osb, credits + xattr_credits); | ||
| 1575 | if (IS_ERR(handle)) { | 1645 | if (IS_ERR(handle)) { |
| 1576 | status = PTR_ERR(handle); | 1646 | status = PTR_ERR(handle); |
| 1577 | handle = NULL; | 1647 | handle = NULL; |
| @@ -1632,6 +1702,15 @@ static int ocfs2_symlink(struct inode *dir, | |||
| 1632 | } | 1702 | } |
| 1633 | } | 1703 | } |
| 1634 | 1704 | ||
| 1705 | if (si.enable) { | ||
| 1706 | status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si, | ||
| 1707 | xattr_ac, data_ac); | ||
| 1708 | if (status < 0) { | ||
| 1709 | mlog_errno(status); | ||
| 1710 | goto bail; | ||
| 1711 | } | ||
| 1712 | } | ||
| 1713 | |||
| 1635 | status = ocfs2_add_entry(handle, dentry, inode, | 1714 | status = ocfs2_add_entry(handle, dentry, inode, |
| 1636 | le64_to_cpu(fe->i_blkno), parent_fe_bh, | 1715 | le64_to_cpu(fe->i_blkno), parent_fe_bh, |
| 1637 | de_bh); | 1716 | de_bh); |
| @@ -1658,10 +1737,14 @@ bail: | |||
| 1658 | brelse(new_fe_bh); | 1737 | brelse(new_fe_bh); |
| 1659 | brelse(parent_fe_bh); | 1738 | brelse(parent_fe_bh); |
| 1660 | brelse(de_bh); | 1739 | brelse(de_bh); |
| 1740 | kfree(si.name); | ||
| 1741 | kfree(si.value); | ||
| 1661 | if (inode_ac) | 1742 | if (inode_ac) |
| 1662 | ocfs2_free_alloc_context(inode_ac); | 1743 | ocfs2_free_alloc_context(inode_ac); |
| 1663 | if (data_ac) | 1744 | if (data_ac) |
| 1664 | ocfs2_free_alloc_context(data_ac); | 1745 | ocfs2_free_alloc_context(data_ac); |
| 1746 | if (xattr_ac) | ||
| 1747 | ocfs2_free_alloc_context(xattr_ac); | ||
| 1665 | if ((status < 0) && inode) { | 1748 | if ((status < 0) && inode) { |
| 1666 | clear_nlink(inode); | 1749 | clear_nlink(inode); |
| 1667 | iput(inode); | 1750 | iput(inode); |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index db03162914cc..2cab0d6615f9 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
| @@ -81,6 +81,9 @@ struct ocfs2_xattr_set_ctxt { | |||
| 81 | 81 | ||
| 82 | #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) | 82 | #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) |
| 83 | #define OCFS2_XATTR_INLINE_SIZE 80 | 83 | #define OCFS2_XATTR_INLINE_SIZE 80 |
| 84 | #define OCFS2_XATTR_FREE_IN_IBODY (OCFS2_MIN_XATTR_INLINE_SIZE \ | ||
| 85 | - sizeof(struct ocfs2_xattr_header) \ | ||
| 86 | - sizeof(__u32)) | ||
| 84 | 87 | ||
| 85 | static struct ocfs2_xattr_def_value_root def_xv = { | 88 | static struct ocfs2_xattr_def_value_root def_xv = { |
| 86 | .xv.xr_list.l_count = cpu_to_le16(1), | 89 | .xv.xr_list.l_count = cpu_to_le16(1), |
| @@ -343,6 +346,52 @@ static void ocfs2_xattr_hash_entry(struct inode *inode, | |||
| 343 | return; | 346 | return; |
| 344 | } | 347 | } |
| 345 | 348 | ||
| 349 | static int ocfs2_xattr_entry_real_size(int name_len, size_t value_len) | ||
| 350 | { | ||
| 351 | int size = 0; | ||
| 352 | |||
| 353 | if (value_len <= OCFS2_XATTR_INLINE_SIZE) | ||
| 354 | size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(value_len); | ||
| 355 | else | ||
| 356 | size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE; | ||
| 357 | size += sizeof(struct ocfs2_xattr_entry); | ||
| 358 | |||
| 359 | return size; | ||
| 360 | } | ||
| 361 | |||
| 362 | int ocfs2_calc_security_init(struct inode *dir, | ||
| 363 | struct ocfs2_security_xattr_info *si, | ||
| 364 | int *want_clusters, | ||
| 365 | int *xattr_credits, | ||
| 366 | struct ocfs2_alloc_context **xattr_ac) | ||
| 367 | { | ||
| 368 | int ret = 0; | ||
| 369 | struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); | ||
| 370 | int s_size = ocfs2_xattr_entry_real_size(strlen(si->name), | ||
| 371 | si->value_len); | ||
| 372 | |||
| 373 | /* | ||
| 374 | * The max space of security xattr taken inline is | ||
| 375 | * 256(name) + 80(value) + 16(entry) = 352 bytes, | ||
| 376 | * So reserve one metadata block for it is ok. | ||
| 377 | */ | ||
| 378 | if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE || | ||
| 379 | s_size > OCFS2_XATTR_FREE_IN_IBODY) { | ||
| 380 | ret = ocfs2_reserve_new_metadata_blocks(osb, 1, xattr_ac); | ||
| 381 | if (ret) { | ||
| 382 | mlog_errno(ret); | ||
| 383 | return ret; | ||
| 384 | } | ||
| 385 | *xattr_credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS; | ||
| 386 | } | ||
| 387 | |||
| 388 | /* reserve clusters for xattr value which will be set in B tree*/ | ||
| 389 | if (si->value_len > OCFS2_XATTR_INLINE_SIZE) | ||
| 390 | *want_clusters += ocfs2_clusters_for_bytes(dir->i_sb, | ||
| 391 | si->value_len); | ||
| 392 | return ret; | ||
| 393 | } | ||
| 394 | |||
| 346 | static int ocfs2_xattr_extend_allocation(struct inode *inode, | 395 | static int ocfs2_xattr_extend_allocation(struct inode *inode, |
| 347 | u32 clusters_to_add, | 396 | u32 clusters_to_add, |
| 348 | struct buffer_head *xattr_bh, | 397 | struct buffer_head *xattr_bh, |
| @@ -5016,6 +5065,27 @@ static int ocfs2_xattr_security_set(struct inode *inode, const char *name, | |||
| 5016 | size, flags); | 5065 | size, flags); |
| 5017 | } | 5066 | } |
| 5018 | 5067 | ||
| 5068 | int ocfs2_init_security_get(struct inode *inode, | ||
| 5069 | struct inode *dir, | ||
| 5070 | struct ocfs2_security_xattr_info *si) | ||
| 5071 | { | ||
| 5072 | return security_inode_init_security(inode, dir, &si->name, &si->value, | ||
| 5073 | &si->value_len); | ||
| 5074 | } | ||
| 5075 | |||
| 5076 | int ocfs2_init_security_set(handle_t *handle, | ||
| 5077 | struct inode *inode, | ||
| 5078 | struct buffer_head *di_bh, | ||
| 5079 | struct ocfs2_security_xattr_info *si, | ||
| 5080 | struct ocfs2_alloc_context *xattr_ac, | ||
| 5081 | struct ocfs2_alloc_context *data_ac) | ||
| 5082 | { | ||
| 5083 | return ocfs2_xattr_set_handle(handle, inode, di_bh, | ||
| 5084 | OCFS2_XATTR_INDEX_SECURITY, | ||
| 5085 | si->name, si->value, si->value_len, 0, | ||
| 5086 | xattr_ac, data_ac); | ||
| 5087 | } | ||
| 5088 | |||
| 5019 | struct xattr_handler ocfs2_xattr_security_handler = { | 5089 | struct xattr_handler ocfs2_xattr_security_handler = { |
| 5020 | .prefix = XATTR_SECURITY_PREFIX, | 5090 | .prefix = XATTR_SECURITY_PREFIX, |
| 5021 | .list = ocfs2_xattr_security_list, | 5091 | .list = ocfs2_xattr_security_list, |
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h index 55c5256ff563..188ef6ba6836 100644 --- a/fs/ocfs2/xattr.h +++ b/fs/ocfs2/xattr.h | |||
| @@ -30,6 +30,13 @@ enum ocfs2_xattr_type { | |||
| 30 | OCFS2_XATTR_MAX | 30 | OCFS2_XATTR_MAX |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | struct ocfs2_security_xattr_info { | ||
| 34 | int enable; | ||
| 35 | char *name; | ||
| 36 | void *value; | ||
| 37 | size_t value_len; | ||
| 38 | }; | ||
| 39 | |||
| 33 | extern struct xattr_handler ocfs2_xattr_user_handler; | 40 | extern struct xattr_handler ocfs2_xattr_user_handler; |
| 34 | extern struct xattr_handler ocfs2_xattr_trusted_handler; | 41 | extern struct xattr_handler ocfs2_xattr_trusted_handler; |
| 35 | extern struct xattr_handler ocfs2_xattr_security_handler; | 42 | extern struct xattr_handler ocfs2_xattr_security_handler; |
| @@ -43,5 +50,15 @@ int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *, | |||
| 43 | struct ocfs2_alloc_context *, | 50 | struct ocfs2_alloc_context *, |
| 44 | struct ocfs2_alloc_context *); | 51 | struct ocfs2_alloc_context *); |
| 45 | int ocfs2_xattr_remove(struct inode *, struct buffer_head *); | 52 | int ocfs2_xattr_remove(struct inode *, struct buffer_head *); |
| 53 | int ocfs2_init_security_get(struct inode *, struct inode *, | ||
| 54 | struct ocfs2_security_xattr_info *); | ||
| 55 | int ocfs2_init_security_set(handle_t *, struct inode *, | ||
| 56 | struct buffer_head *, | ||
| 57 | struct ocfs2_security_xattr_info *, | ||
| 58 | struct ocfs2_alloc_context *, | ||
| 59 | struct ocfs2_alloc_context *); | ||
| 60 | int ocfs2_calc_security_init(struct inode *, | ||
| 61 | struct ocfs2_security_xattr_info *, | ||
| 62 | int *, int *, struct ocfs2_alloc_context **); | ||
| 46 | 63 | ||
| 47 | #endif /* OCFS2_XATTR_H */ | 64 | #endif /* OCFS2_XATTR_H */ |
