Index: linux-2.4.24/fs/ext3/ialloc.c =================================================================== --- linux-2.4.24.orig/fs/ext3/ialloc.c 2004-08-02 22:13:13.000000000 +0400 +++ linux-2.4.24/fs/ext3/ialloc.c 2004-08-04 01:10:30.000000000 +0400 @@ -41,6 +41,24 @@ * when a file system is mounted (see ext3_read_super). */ +/* + * this is very simple policy: files with O_INRESERVE goes to last group; + * files with no O_INRESERVE goes to all groups, but last. probably we'll + * specify group for O_INRESERVE files later -bzzz */ +static inline int ext3_group_allowed(struct super_block *sb, int mode, int group) +{ + if (!test_opt(sb, INRESERVE) || EXT3_SB(sb)->s_groups_count == 1) + return 1; + + if (mode & EXT3_S_INRESERVE) { + if (group != EXT3_SB(sb)->s_groups_count - 1) + return 0; + } else { + if (group == EXT3_SB(sb)->s_groups_count -1 ) + return 0; + } + return 1; +} /* * Read the inode allocation bitmap for a given block_group, reading @@ -337,20 +355,33 @@ return !ext3_test_bit(nr, bh2jh(bh)->b_committed_data); } -int ext3_find_group_dir(const struct inode *dir, +int ext3_find_group_dir(const struct inode *dir, int mode, struct ext3_group_desc **gdp, struct buffer_head **bh) { struct super_block *sb = dir->i_sb; struct ext3_super_block *es; struct ext3_group_desc *tmp; - int i = 0, j, avefreei; + int i = 0, j, ifree, avefreei; es = EXT3_SB(sb)->s_es; - avefreei = le32_to_cpu(es->s_free_inodes_count) / - sb->u.ext3_sb.s_groups_count; + ifree = le32_to_cpu(es->s_free_inodes_count); + j = sb->u.ext3_sb.s_groups_count; + if (test_opt(sb, INRESERVE) && EXT3_SB(sb)->s_groups_count > 1) { + tmp = ext3_get_group_desc(sb, EXT3_SB(sb)->s_groups_count-1, NULL); + if (mode & EXT3_S_INRESERVE) { + ifree = le16_to_cpu(tmp->bg_free_blocks_count); + j = 1; + } else { + ifree -= le16_to_cpu(tmp->bg_free_blocks_count); + j--; + } + } + avefreei = ifree / j; for (j = 0; j < sb->u.ext3_sb.s_groups_count; j++) { struct buffer_head *temp_buffer; + if (!ext3_group_allowed(sb, mode, j)) + continue; tmp = ext3_get_group_desc(sb, j, &temp_buffer); if (tmp && le16_to_cpu(tmp->bg_free_inodes_count) && le16_to_cpu(tmp->bg_free_inodes_count) >= avefreei) { @@ -366,7 +397,7 @@ return i; } -int ext3_find_group_other(const struct inode *dir, +int ext3_find_group_other(const struct inode *dir, int mode, struct ext3_group_desc **gdp, struct buffer_head **bh) { @@ -379,7 +410,8 @@ */ i = dir->u.ext3_i.i_block_group; tmp = ext3_get_group_desc(sb, i, bh); - if (tmp && le16_to_cpu(tmp->bg_free_inodes_count)) + if (tmp && le16_to_cpu(tmp->bg_free_inodes_count) + && ext3_group_allowed(sb, mode, i)) *gdp = tmp; else { /* @@ -390,6 +422,8 @@ i += j; if (i >= sb->u.ext3_sb.s_groups_count) i -= sb->u.ext3_sb.s_groups_count; + if (!ext3_group_allowed(sb, mode, i)) + continue; tmp = ext3_get_group_desc (sb, i, bh); if (tmp && le16_to_cpu(tmp->bg_free_inodes_count)) { *gdp = tmp; @@ -405,6 +439,8 @@ for (j = 2; j < sb->u.ext3_sb.s_groups_count; j++) { if (++i >= sb->u.ext3_sb.s_groups_count) i = 0; + if (!ext3_group_allowed(sb, mode, i)) + continue; tmp = ext3_get_group_desc (sb, i, bh); if (tmp && le16_to_cpu(tmp->bg_free_inodes_count)) { *gdp = tmp; @@ -421,8 +457,8 @@ struct buffer_head **bh) { if (S_ISDIR(mode)) - return ext3_find_group_dir(dir, gdp, bh); - return ext3_find_group_other(dir, gdp, bh); + return ext3_find_group_dir(dir, mode, gdp, bh); + return ext3_find_group_other(dir, mode, gdp, bh); } static int ext3_find_usable_inode(struct super_block *sb, @@ -549,6 +585,8 @@ for (i = i + 1; i != k; i++) { if (i >= sb->u.ext3_sb.s_groups_count) i = 0; + if (!ext3_group_allowed(sb, mode, i)) + continue; tmp = ext3_get_group_desc(sb, i, &bh2); if (le16_to_cpu(tmp->bg_free_inodes_count) == 0) continue; @@ -588,6 +626,7 @@ if (buffer_jbd(bh) && bh2jh(bh)->b_committed_data) J_ASSERT_BH(bh, !ext3_test_bit(j, bh2jh(bh)->b_committed_data)); + J_ASSERT(ext3_group_allowed(sb, mode, i)); j += i * EXT3_INODES_PER_GROUP(sb) + 1; if (j < EXT3_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) { ext3_error (sb, "ext3_new_inode", @@ -628,7 +667,7 @@ mode |= S_ISGID; } else inode->i_gid = current->fsgid; - inode->i_mode = mode; + inode->i_mode = mode & ~EXT3_S_INRESERVE; inode->i_ino = j; /* This is the optimal IO size (for stat), not the fs block size */ Index: linux-2.4.24/fs/ext3/super.c =================================================================== --- linux-2.4.24.orig/fs/ext3/super.c 2004-08-02 22:13:12.000000000 +0400 +++ linux-2.4.24/fs/ext3/super.c 2004-08-04 00:10:07.000000000 +0400 @@ -723,6 +723,10 @@ return 0; *resgid = v; } + else if (!strcmp (this_char, "inrsv")) { + set_opt (*mount_options, INRESERVE); + J_ASSERT((EXT3_S_INRESERVE & S_IALLUGO) == 0); + } else if (!strcmp (this_char, "resuid")) { unsigned long v; if (want_numeric(value, "resuid", &v)) Index: linux-2.4.24/fs/ext3/namei.c =================================================================== --- linux-2.4.24.orig/fs/ext3/namei.c 2004-08-02 22:13:13.000000000 +0400 +++ linux-2.4.24/fs/ext3/namei.c 2004-08-03 03:21:09.000000000 +0400 @@ -1971,6 +1971,36 @@ return err; } +static int ext3_create_it (struct inode * dir, struct dentry * dentry, int mode, + struct lookup_intent *it) +{ + handle_t *handle; + struct inode * inode; + int err; + + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3); + if (IS_ERR(handle)) { + return PTR_ERR(handle); + } + + if (IS_SYNC(dir)) + handle->h_sync = 1; + + if (it && it->it_flags & O_INRESERVE) + mode |= EXT3_S_INRESERVE; + inode = ext3_new_inode_wantedi (handle, dir, mode, dentry); + err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + inode->i_op = &ext3_file_inode_operations; + inode->i_fop = &ext3_file_operations; + inode->i_mapping->a_ops = &ext3_aops; + err = ext3_add_nondir(handle, dentry, inode); + } + ext3_journal_stop(handle, dir); + return err; +} + static int ext3_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev) { @@ -2803,6 +2833,7 @@ */ struct inode_operations ext3_dir_inode_operations = { create: ext3_create, /* BKL held */ + create_it: ext3_create_it, /* BKL held */ lookup: ext3_lookup, /* BKL held */ lookup_raw: ext3_lookup_raw, /* BKL held */ link: ext3_link, /* BKL held */ Index: linux-2.4.24/include/asm-i386/fcntl.h =================================================================== --- linux-2.4.24.orig/include/asm-i386/fcntl.h 2001-09-18 00:16:30.000000000 +0400 +++ linux-2.4.24/include/asm-i386/fcntl.h 2004-08-03 01:20:55.000000000 +0400 @@ -20,6 +20,7 @@ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_INRESERVE 01000000 /* allocate inodes in reserved space */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ Index: linux-2.4.24/include/linux/ext3_fs.h =================================================================== --- linux-2.4.24.orig/include/linux/ext3_fs.h 2004-08-02 22:13:12.000000000 +0400 +++ linux-2.4.24/include/linux/ext3_fs.h 2004-08-03 01:03:39.000000000 +0400 @@ -343,6 +343,7 @@ #define EXT3_MOUNT_ASYNCDEL 0x20000 /* Delayed deletion */ #define EXT3_MOUNT_EXTENTS 0x100000/* Extents support */ #define EXT3_MOUNT_EXTDEBUG 0x200000/* Extents debug */ +#define EXT3_MOUNT_INRESERVE 0x400000/* reserve one group for O_INRESERVE */ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H @@ -482,6 +483,8 @@ #define EXT3_GOOD_OLD_INODE_SIZE 128 +#define EXT3_S_INRESERVE 01000000 + /* * Feature set definitions */