diff options
| -rw-r--r-- | fs/ocfs2/file.c | 182 | ||||
| -rw-r--r-- | fs/ocfs2/file.h | 3 | ||||
| -rw-r--r-- | fs/ocfs2/ioctl.c | 15 | ||||
| -rw-r--r-- | fs/ocfs2/ocfs2_fs.h | 26 | ||||
| -rw-r--r-- | fs/ocfs2/super.c | 4 | ||||
| -rw-r--r-- | fs/ocfs2/super.h | 2 |
6 files changed, 216 insertions, 16 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 11f7cf9f2511..f04c7aa834cb 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
| @@ -1111,17 +1111,16 @@ out: | |||
| 1111 | return ret; | 1111 | return ret; |
| 1112 | } | 1112 | } |
| 1113 | 1113 | ||
| 1114 | static int ocfs2_write_remove_suid(struct inode *inode) | 1114 | static int __ocfs2_write_remove_suid(struct inode *inode, |
| 1115 | struct buffer_head *bh) | ||
| 1115 | { | 1116 | { |
| 1116 | int ret; | 1117 | int ret; |
| 1117 | struct buffer_head *bh = NULL; | ||
| 1118 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
| 1119 | handle_t *handle; | 1118 | handle_t *handle; |
| 1120 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 1119 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
| 1121 | struct ocfs2_dinode *di; | 1120 | struct ocfs2_dinode *di; |
| 1122 | 1121 | ||
| 1123 | mlog_entry("(Inode %llu, mode 0%o)\n", | 1122 | mlog_entry("(Inode %llu, mode 0%o)\n", |
| 1124 | (unsigned long long)oi->ip_blkno, inode->i_mode); | 1123 | (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_mode); |
| 1125 | 1124 | ||
| 1126 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); | 1125 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); |
| 1127 | if (handle == NULL) { | 1126 | if (handle == NULL) { |
| @@ -1130,17 +1129,11 @@ static int ocfs2_write_remove_suid(struct inode *inode) | |||
| 1130 | goto out; | 1129 | goto out; |
| 1131 | } | 1130 | } |
| 1132 | 1131 | ||
| 1133 | ret = ocfs2_read_block(osb, oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode); | ||
| 1134 | if (ret < 0) { | ||
| 1135 | mlog_errno(ret); | ||
| 1136 | goto out_trans; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | ret = ocfs2_journal_access(handle, inode, bh, | 1132 | ret = ocfs2_journal_access(handle, inode, bh, |
| 1140 | OCFS2_JOURNAL_ACCESS_WRITE); | 1133 | OCFS2_JOURNAL_ACCESS_WRITE); |
| 1141 | if (ret < 0) { | 1134 | if (ret < 0) { |
| 1142 | mlog_errno(ret); | 1135 | mlog_errno(ret); |
| 1143 | goto out_bh; | 1136 | goto out_trans; |
| 1144 | } | 1137 | } |
| 1145 | 1138 | ||
| 1146 | inode->i_mode &= ~S_ISUID; | 1139 | inode->i_mode &= ~S_ISUID; |
| @@ -1153,8 +1146,7 @@ static int ocfs2_write_remove_suid(struct inode *inode) | |||
| 1153 | ret = ocfs2_journal_dirty(handle, bh); | 1146 | ret = ocfs2_journal_dirty(handle, bh); |
| 1154 | if (ret < 0) | 1147 | if (ret < 0) |
| 1155 | mlog_errno(ret); | 1148 | mlog_errno(ret); |
| 1156 | out_bh: | 1149 | |
| 1157 | brelse(bh); | ||
| 1158 | out_trans: | 1150 | out_trans: |
| 1159 | ocfs2_commit_trans(osb, handle); | 1151 | ocfs2_commit_trans(osb, handle); |
| 1160 | out: | 1152 | out: |
| @@ -1200,6 +1192,25 @@ out: | |||
| 1200 | return ret; | 1192 | return ret; |
| 1201 | } | 1193 | } |
| 1202 | 1194 | ||
| 1195 | static int ocfs2_write_remove_suid(struct inode *inode) | ||
| 1196 | { | ||
| 1197 | int ret; | ||
| 1198 | struct buffer_head *bh = NULL; | ||
| 1199 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
| 1200 | |||
| 1201 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | ||
| 1202 | oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode); | ||
| 1203 | if (ret < 0) { | ||
| 1204 | mlog_errno(ret); | ||
| 1205 | goto out; | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | ret = __ocfs2_write_remove_suid(inode, bh); | ||
| 1209 | out: | ||
| 1210 | brelse(bh); | ||
| 1211 | return ret; | ||
| 1212 | } | ||
| 1213 | |||
| 1203 | /* | 1214 | /* |
| 1204 | * Allocate enough extents to cover the region starting at byte offset | 1215 | * Allocate enough extents to cover the region starting at byte offset |
| 1205 | * start for len bytes. Existing extents are skipped, any extents | 1216 | * start for len bytes. Existing extents are skipped, any extents |
| @@ -1490,6 +1501,151 @@ out: | |||
| 1490 | return ret; | 1501 | return ret; |
| 1491 | } | 1502 | } |
| 1492 | 1503 | ||
| 1504 | /* | ||
| 1505 | * Parts of this function taken from xfs_change_file_space() | ||
| 1506 | */ | ||
| 1507 | int ocfs2_change_file_space(struct file *file, unsigned int cmd, | ||
| 1508 | struct ocfs2_space_resv *sr) | ||
| 1509 | { | ||
| 1510 | int ret; | ||
| 1511 | s64 llen; | ||
| 1512 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 1513 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
| 1514 | struct buffer_head *di_bh = NULL; | ||
| 1515 | handle_t *handle; | ||
| 1516 | unsigned long long max_off = ocfs2_max_file_offset(inode->i_sb->s_blocksize_bits); | ||
| 1517 | |||
| 1518 | if ((cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) && | ||
| 1519 | !ocfs2_writes_unwritten_extents(osb)) | ||
| 1520 | return -ENOTTY; | ||
| 1521 | else if ((cmd == OCFS2_IOC_UNRESVSP || cmd == OCFS2_IOC_UNRESVSP64) && | ||
| 1522 | !ocfs2_sparse_alloc(osb)) | ||
| 1523 | return -ENOTTY; | ||
| 1524 | |||
| 1525 | if (!S_ISREG(inode->i_mode)) | ||
| 1526 | return -EINVAL; | ||
| 1527 | |||
| 1528 | if (!(file->f_mode & FMODE_WRITE)) | ||
| 1529 | return -EBADF; | ||
| 1530 | |||
| 1531 | if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) | ||
| 1532 | return -EROFS; | ||
| 1533 | |||
| 1534 | mutex_lock(&inode->i_mutex); | ||
| 1535 | |||
| 1536 | /* | ||
| 1537 | * This prevents concurrent writes on other nodes | ||
| 1538 | */ | ||
| 1539 | ret = ocfs2_rw_lock(inode, 1); | ||
| 1540 | if (ret) { | ||
| 1541 | mlog_errno(ret); | ||
| 1542 | goto out; | ||
| 1543 | } | ||
| 1544 | |||
| 1545 | ret = ocfs2_meta_lock(inode, &di_bh, 1); | ||
| 1546 | if (ret) { | ||
| 1547 | mlog_errno(ret); | ||
| 1548 | goto out_rw_unlock; | ||
| 1549 | } | ||
| 1550 | |||
| 1551 | if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) { | ||
| 1552 | ret = -EPERM; | ||
| 1553 | goto out_meta_unlock; | ||
| 1554 | } | ||
| 1555 | |||
| 1556 | switch (sr->l_whence) { | ||
| 1557 | case 0: /*SEEK_SET*/ | ||
| 1558 | break; | ||
| 1559 | case 1: /*SEEK_CUR*/ | ||
| 1560 | sr->l_start += file->f_pos; | ||
| 1561 | break; | ||
| 1562 | case 2: /*SEEK_END*/ | ||
| 1563 | sr->l_start += i_size_read(inode); | ||
| 1564 | break; | ||
| 1565 | default: | ||
| 1566 | ret = -EINVAL; | ||
| 1567 | goto out_meta_unlock; | ||
| 1568 | } | ||
| 1569 | sr->l_whence = 0; | ||
| 1570 | |||
| 1571 | llen = sr->l_len > 0 ? sr->l_len - 1 : sr->l_len; | ||
| 1572 | |||
| 1573 | if (sr->l_start < 0 | ||
| 1574 | || sr->l_start > max_off | ||
| 1575 | || (sr->l_start + llen) < 0 | ||
| 1576 | || (sr->l_start + llen) > max_off) { | ||
| 1577 | ret = -EINVAL; | ||
| 1578 | goto out_meta_unlock; | ||
| 1579 | } | ||
| 1580 | |||
| 1581 | if (cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) { | ||
| 1582 | if (sr->l_len <= 0) { | ||
| 1583 | ret = -EINVAL; | ||
| 1584 | goto out_meta_unlock; | ||
| 1585 | } | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | if (should_remove_suid(file->f_path.dentry)) { | ||
| 1589 | ret = __ocfs2_write_remove_suid(inode, di_bh); | ||
| 1590 | if (ret) { | ||
| 1591 | mlog_errno(ret); | ||
| 1592 | goto out_meta_unlock; | ||
| 1593 | } | ||
| 1594 | } | ||
| 1595 | |||
| 1596 | down_write(&OCFS2_I(inode)->ip_alloc_sem); | ||
| 1597 | switch (cmd) { | ||
| 1598 | case OCFS2_IOC_RESVSP: | ||
| 1599 | case OCFS2_IOC_RESVSP64: | ||
| 1600 | /* | ||
| 1601 | * This takes unsigned offsets, but the signed ones we | ||
| 1602 | * pass have been checked against overflow above. | ||
| 1603 | */ | ||
| 1604 | ret = ocfs2_allocate_unwritten_extents(inode, sr->l_start, | ||
| 1605 | sr->l_len); | ||
| 1606 | break; | ||
| 1607 | case OCFS2_IOC_UNRESVSP: | ||
| 1608 | case OCFS2_IOC_UNRESVSP64: | ||
| 1609 | ret = ocfs2_remove_inode_range(inode, di_bh, sr->l_start, | ||
| 1610 | sr->l_len); | ||
| 1611 | break; | ||
| 1612 | default: | ||
| 1613 | ret = -EINVAL; | ||
| 1614 | } | ||
| 1615 | up_write(&OCFS2_I(inode)->ip_alloc_sem); | ||
| 1616 | if (ret) { | ||
| 1617 | mlog_errno(ret); | ||
| 1618 | goto out_meta_unlock; | ||
| 1619 | } | ||
| 1620 | |||
| 1621 | /* | ||
| 1622 | * We update c/mtime for these changes | ||
| 1623 | */ | ||
| 1624 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); | ||
| 1625 | if (IS_ERR(handle)) { | ||
| 1626 | ret = PTR_ERR(handle); | ||
| 1627 | mlog_errno(ret); | ||
| 1628 | goto out_meta_unlock; | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; | ||
| 1632 | ret = ocfs2_mark_inode_dirty(handle, inode, di_bh); | ||
| 1633 | if (ret < 0) | ||
| 1634 | mlog_errno(ret); | ||
| 1635 | |||
| 1636 | ocfs2_commit_trans(osb, handle); | ||
| 1637 | |||
| 1638 | out_meta_unlock: | ||
| 1639 | brelse(di_bh); | ||
| 1640 | ocfs2_meta_unlock(inode, 1); | ||
| 1641 | out_rw_unlock: | ||
| 1642 | ocfs2_rw_unlock(inode, 1); | ||
| 1643 | |||
| 1644 | mutex_unlock(&inode->i_mutex); | ||
| 1645 | out: | ||
| 1646 | return ret; | ||
| 1647 | } | ||
| 1648 | |||
| 1493 | static int ocfs2_prepare_inode_for_write(struct dentry *dentry, | 1649 | static int ocfs2_prepare_inode_for_write(struct dentry *dentry, |
| 1494 | loff_t *ppos, | 1650 | loff_t *ppos, |
| 1495 | size_t count, | 1651 | size_t count, |
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h index 79115c92dc30..36fe27f268ee 100644 --- a/fs/ocfs2/file.h +++ b/fs/ocfs2/file.h | |||
| @@ -62,4 +62,7 @@ int ocfs2_should_update_atime(struct inode *inode, | |||
| 62 | int ocfs2_update_inode_atime(struct inode *inode, | 62 | int ocfs2_update_inode_atime(struct inode *inode, |
| 63 | struct buffer_head *bh); | 63 | struct buffer_head *bh); |
| 64 | 64 | ||
| 65 | int ocfs2_change_file_space(struct file *file, unsigned int cmd, | ||
| 66 | struct ocfs2_space_resv *sr); | ||
| 67 | |||
| 65 | #endif /* OCFS2_FILE_H */ | 68 | #endif /* OCFS2_FILE_H */ |
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index f3ad21ad9aed..bd68c3f2afbe 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "ocfs2.h" | 14 | #include "ocfs2.h" |
| 15 | #include "alloc.h" | 15 | #include "alloc.h" |
| 16 | #include "dlmglue.h" | 16 | #include "dlmglue.h" |
| 17 | #include "file.h" | ||
| 17 | #include "inode.h" | 18 | #include "inode.h" |
| 18 | #include "journal.h" | 19 | #include "journal.h" |
| 19 | 20 | ||
| @@ -115,6 +116,7 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp, | |||
| 115 | { | 116 | { |
| 116 | unsigned int flags; | 117 | unsigned int flags; |
| 117 | int status; | 118 | int status; |
| 119 | struct ocfs2_space_resv sr; | ||
| 118 | 120 | ||
| 119 | switch (cmd) { | 121 | switch (cmd) { |
| 120 | case OCFS2_IOC_GETFLAGS: | 122 | case OCFS2_IOC_GETFLAGS: |
| @@ -130,6 +132,14 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp, | |||
| 130 | 132 | ||
| 131 | return ocfs2_set_inode_attr(inode, flags, | 133 | return ocfs2_set_inode_attr(inode, flags, |
| 132 | OCFS2_FL_MODIFIABLE); | 134 | OCFS2_FL_MODIFIABLE); |
| 135 | case OCFS2_IOC_RESVSP: | ||
| 136 | case OCFS2_IOC_RESVSP64: | ||
| 137 | case OCFS2_IOC_UNRESVSP: | ||
| 138 | case OCFS2_IOC_UNRESVSP64: | ||
| 139 | if (copy_from_user(&sr, (int __user *) arg, sizeof(sr))) | ||
| 140 | return -EFAULT; | ||
| 141 | |||
| 142 | return ocfs2_change_file_space(filp, cmd, &sr); | ||
| 133 | default: | 143 | default: |
| 134 | return -ENOTTY; | 144 | return -ENOTTY; |
| 135 | } | 145 | } |
| @@ -148,6 +158,11 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
| 148 | case OCFS2_IOC32_SETFLAGS: | 158 | case OCFS2_IOC32_SETFLAGS: |
| 149 | cmd = OCFS2_IOC_SETFLAGS; | 159 | cmd = OCFS2_IOC_SETFLAGS; |
| 150 | break; | 160 | break; |
| 161 | case OCFS2_IOC_RESVSP: | ||
| 162 | case OCFS2_IOC_RESVSP64: | ||
| 163 | case OCFS2_IOC_UNRESVSP: | ||
| 164 | case OCFS2_IOC_UNRESVSP64: | ||
| 165 | break; | ||
| 151 | default: | 166 | default: |
| 152 | return -ENOIOCTLCMD; | 167 | return -ENOIOCTLCMD; |
| 153 | } | 168 | } |
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index c20a74b99d87..82f8a75b207e 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h | |||
| @@ -175,6 +175,32 @@ | |||
| 175 | #define OCFS2_IOC32_SETFLAGS _IOW('f', 2, int) | 175 | #define OCFS2_IOC32_SETFLAGS _IOW('f', 2, int) |
| 176 | 176 | ||
| 177 | /* | 177 | /* |
| 178 | * Space reservation / allocation / free ioctls and argument structure | ||
| 179 | * are designed to be compatible with XFS. | ||
| 180 | * | ||
| 181 | * ALLOCSP* and FREESP* are not and will never be supported, but are | ||
| 182 | * included here for completeness. | ||
| 183 | */ | ||
| 184 | struct ocfs2_space_resv { | ||
| 185 | __s16 l_type; | ||
| 186 | __s16 l_whence; | ||
| 187 | __s64 l_start; | ||
| 188 | __s64 l_len; /* len == 0 means until end of file */ | ||
| 189 | __s32 l_sysid; | ||
| 190 | __u32 l_pid; | ||
| 191 | __s32 l_pad[4]; /* reserve area */ | ||
| 192 | }; | ||
| 193 | |||
| 194 | #define OCFS2_IOC_ALLOCSP _IOW ('X', 10, struct ocfs2_space_resv) | ||
| 195 | #define OCFS2_IOC_FREESP _IOW ('X', 11, struct ocfs2_space_resv) | ||
| 196 | #define OCFS2_IOC_RESVSP _IOW ('X', 40, struct ocfs2_space_resv) | ||
| 197 | #define OCFS2_IOC_UNRESVSP _IOW ('X', 41, struct ocfs2_space_resv) | ||
| 198 | #define OCFS2_IOC_ALLOCSP64 _IOW ('X', 36, struct ocfs2_space_resv) | ||
| 199 | #define OCFS2_IOC_FREESP64 _IOW ('X', 37, struct ocfs2_space_resv) | ||
| 200 | #define OCFS2_IOC_RESVSP64 _IOW ('X', 42, struct ocfs2_space_resv) | ||
| 201 | #define OCFS2_IOC_UNRESVSP64 _IOW ('X', 43, struct ocfs2_space_resv) | ||
| 202 | |||
| 203 | /* | ||
| 178 | * Journal Flags (ocfs2_dinode.id1.journal1.i_flags) | 204 | * Journal Flags (ocfs2_dinode.id1.journal1.i_flags) |
| 179 | */ | 205 | */ |
| 180 | #define OCFS2_JOURNAL_DIRTY_FL (0x00000001) /* Journal needs recovery */ | 206 | #define OCFS2_JOURNAL_DIRTY_FL (0x00000001) /* Journal needs recovery */ |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index f07718a7552b..3a5a1ed09ac9 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
| @@ -115,8 +115,6 @@ static void ocfs2_write_super(struct super_block *sb); | |||
| 115 | static struct inode *ocfs2_alloc_inode(struct super_block *sb); | 115 | static struct inode *ocfs2_alloc_inode(struct super_block *sb); |
| 116 | static void ocfs2_destroy_inode(struct inode *inode); | 116 | static void ocfs2_destroy_inode(struct inode *inode); |
| 117 | 117 | ||
| 118 | static unsigned long long ocfs2_max_file_offset(unsigned int blockshift); | ||
| 119 | |||
| 120 | static const struct super_operations ocfs2_sops = { | 118 | static const struct super_operations ocfs2_sops = { |
| 121 | .statfs = ocfs2_statfs, | 119 | .statfs = ocfs2_statfs, |
| 122 | .alloc_inode = ocfs2_alloc_inode, | 120 | .alloc_inode = ocfs2_alloc_inode, |
| @@ -321,7 +319,7 @@ static void ocfs2_destroy_inode(struct inode *inode) | |||
| 321 | /* From xfs_super.c:xfs_max_file_offset | 319 | /* From xfs_super.c:xfs_max_file_offset |
| 322 | * Copyright (c) 2000-2004 Silicon Graphics, Inc. | 320 | * Copyright (c) 2000-2004 Silicon Graphics, Inc. |
| 323 | */ | 321 | */ |
| 324 | static unsigned long long ocfs2_max_file_offset(unsigned int blockshift) | 322 | unsigned long long ocfs2_max_file_offset(unsigned int blockshift) |
| 325 | { | 323 | { |
| 326 | unsigned int pagefactor = 1; | 324 | unsigned int pagefactor = 1; |
| 327 | unsigned int bitshift = BITS_PER_LONG - 1; | 325 | unsigned int bitshift = BITS_PER_LONG - 1; |
diff --git a/fs/ocfs2/super.h b/fs/ocfs2/super.h index 783f5270f2a1..3b9cb3d0b008 100644 --- a/fs/ocfs2/super.h +++ b/fs/ocfs2/super.h | |||
| @@ -45,4 +45,6 @@ void __ocfs2_abort(struct super_block *sb, | |||
| 45 | 45 | ||
| 46 | #define ocfs2_abort(sb, fmt, args...) __ocfs2_abort(sb, __PRETTY_FUNCTION__, fmt, ##args) | 46 | #define ocfs2_abort(sb, fmt, args...) __ocfs2_abort(sb, __PRETTY_FUNCTION__, fmt, ##args) |
| 47 | 47 | ||
| 48 | unsigned long long ocfs2_max_file_offset(unsigned int blockshift); | ||
| 49 | |||
| 48 | #endif /* OCFS2_SUPER_H */ | 50 | #endif /* OCFS2_SUPER_H */ |
