--- /dev/null
+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
+ */