Index: linux-2.6.7/fs/ext3/ialloc.c =================================================================== --- linux-2.6.7.orig/fs/ext3/ialloc.c 2004-08-27 14:28:16.000000000 +0800 +++ linux-2.6.7/fs/ext3/ialloc.c 2004-08-27 14:29:21.000000000 +0800 @@ -43,6 +43,24 @@ * the free blocks count in the block. */ +/* + * 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 @@ -203,7 +221,7 @@ * For other inodes, search forward from the parent directory\'s block * group to find a free inode. */ -static int find_group_dir(struct super_block *sb, struct inode *parent) +static int find_group_dir(struct super_block *sb, struct inode *parent, int mode) { int ngroups = EXT3_SB(sb)->s_groups_count; int freei, avefreei; @@ -215,6 +233,8 @@ avefreei = freei / ngroups; for (group = 0; group < ngroups; group++) { + if (!ext3_group_allowed(sb, mode, group)) + continue; desc = ext3_get_group_desc (sb, group, &bh); if (!desc || !desc->bg_free_inodes_count) continue; @@ -258,7 +278,7 @@ #define INODE_COST 64 #define BLOCK_COST 256 -static int find_group_orlov(struct super_block *sb, struct inode *parent) +static int find_group_orlov(struct super_block *sb, struct inode *parent, int mode) { int parent_group = EXT3_I(parent)->i_block_group; struct ext3_sb_info *sbi = EXT3_SB(sb); @@ -288,6 +308,8 @@ parent_group = (unsigned)group % ngroups; for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; + if (!ext3_group_allowed(sb, mode, group)) + continue; desc = ext3_get_group_desc (sb, group, &bh); if (!desc || !desc->bg_free_inodes_count) continue; @@ -357,7 +379,7 @@ return -1; } -static int find_group_other(struct super_block *sb, struct inode *parent) +static int find_group_other(struct super_block *sb, struct inode *parent, int mode) { int parent_group = EXT3_I(parent)->i_block_group; int ngroups = EXT3_SB(sb)->s_groups_count; @@ -393,6 +415,8 @@ group += i; if (group >= ngroups) group -= ngroups; + if (!ext3_group_allowed(sb, mode, group)) + continue; desc = ext3_get_group_desc (sb, group, &bh); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) @@ -407,6 +431,8 @@ for (i = 0; i < ngroups; i++) { if (++group >= ngroups) group = 0; + if (!ext3_group_allowed(sb, mode, group)) + continue; desc = ext3_get_group_desc (sb, group, &bh); if (desc && le16_to_cpu(desc->bg_free_inodes_count)) return group; @@ -502,40 +528,41 @@ continue_allocation: if (S_ISDIR(mode)) { if (test_opt (sb, OLDALLOC)) - group = find_group_dir(sb, dir); + group = find_group_dir(sb, dir, mode); else - group = find_group_orlov(sb, dir); + group = find_group_orlov(sb, dir, mode); } else - group = find_group_other(sb, dir); + group = find_group_other(sb, dir, mode); err = -ENOSPC; if (group == -1) goto out; for (i = 0; i < sbi->s_groups_count; i++) { - gdp = ext3_get_group_desc(sb, group, &bh2); + if (ext3_group_allowed(sb, mode, group)) { + gdp = ext3_get_group_desc(sb, group, &bh2); - err = -EIO; - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, group); - if (!bitmap_bh) - goto fail; + err = -EIO; + brelse(bitmap_bh); + bitmap_bh = read_inode_bitmap(sb, group); + if (!bitmap_bh) + goto fail; + + ino = 0; + + repeat_in_this_group: + ino = ext3_find_next_zero_bit((unsigned long *) + bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino); + if (ino < EXT3_INODES_PER_GROUP(sb)) { + if (ext3_test_allocatable(ino, bitmap_bh)) { + goto got; + } + J_ASSERT_BH(bitmap_bh, bh2jh(bitmap_bh)->b_committed_data); - ino = 0; - -repeat_in_this_group: - ino = ext3_find_next_zero_bit((unsigned long *) - bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino); - if (ino < EXT3_INODES_PER_GROUP(sb)) { - if (ext3_test_allocatable(ino, bitmap_bh)) { - goto got; + if (++ino < EXT3_INODES_PER_GROUP(sb)) + goto repeat_in_this_group; } - J_ASSERT_BH(bitmap_bh, bh2jh(bitmap_bh)->b_committed_data); - - if (++ino < EXT3_INODES_PER_GROUP(sb)) - goto repeat_in_this_group; } - /* * This case is possible in concurrent environment. It is very * rare. We cannot repeat the find_group_xxx() call because @@ -548,7 +575,6 @@ } err = -ENOSPC; goto out; - got: BUFFER_TRACE(bitmap_bh, "get_undo_access"); err = ext3_journal_get_undo_access(handle, bitmap_bh, NULL); @@ -567,6 +593,7 @@ if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) J_ASSERT_BH(bitmap_bh, !ext3_test_bit(ino, bh2jh(bitmap_bh)->b_committed_data)); + J_ASSERT(ext3_group_allowed(sb, mode, group)); ino += group * EXT3_INODES_PER_GROUP(sb) + 1; if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { ext3_error (sb, "ext3_new_inode", @@ -605,7 +632,7 @@ mode |= S_ISGID; } else inode->i_gid = current->fsgid; - inode->i_mode = mode; + inode->i_mode = mode & ~EXT3_S_INRESERVE; inode->i_ino = ino; /* This is the optimal IO size (for stat), not the fs block size */ Index: linux-2.6.7/fs/ext3/super.c =================================================================== --- linux-2.6.7.orig/fs/ext3/super.c 2004-08-27 12:04:38.000000000 +0800 +++ linux-2.6.7/fs/ext3/super.c 2004-08-27 14:28:22.000000000 +0800 @@ -644,6 +644,7 @@ {Opt_iopen_nopriv, "iopen_nopriv"}, {Opt_extents, "extents"}, {Opt_extdebug, "extdebug"}, + {Opt_inrsv, "inrsv"}, {Opt_err, NULL} }; @@ -929,6 +930,10 @@ case Opt_extdebug: set_opt (sbi->s_mount_opt, EXTDEBUG); break; + case Opt_inrsv: + set_opt (sbi->s_mount_opt, INRESERVE); + J_ASSERT((EXT3_S_INRESERVE & S_IALLUGO) == 0); + break; default: printk (KERN_ERR "EXT3-fs: Unrecognized mount option \"%s\" " Index: linux-2.6.7/fs/ext3/namei.c =================================================================== --- linux-2.6.7.orig/fs/ext3/namei.c 2004-08-27 13:03:21.000000000 +0800 +++ linux-2.6.7/fs/ext3/namei.c 2004-08-27 14:36:09.000000000 +0800 @@ -1701,6 +1701,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; + ext3_set_aops(inode); + 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, dev_t rdev) { @@ -2462,6 +2492,7 @@ */ struct inode_operations ext3_dir_inode_operations = { .create = ext3_create, + .create_it = ext3_create_it, /* BKL held */ .lookup = ext3_lookup, .link = ext3_link, .unlink = ext3_unlink, Index: linux-2.6.7/include/asm-i386/fcntl.h =================================================================== --- linux-2.6.7.orig/include/asm-i386/fcntl.h 2004-06-16 13:19:35.000000000 +0800 +++ linux-2.6.7/include/asm-i386/fcntl.h 2004-08-27 14:28:22.000000000 +0800 @@ -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.6.7/include/linux/ext3_fs.h =================================================================== --- linux-2.6.7.orig/include/linux/ext3_fs.h 2004-08-27 13:03:21.000000000 +0800 +++ linux-2.6.7/include/linux/ext3_fs.h 2004-08-27 14:28:22.000000000 +0800 @@ -343,6 +343,7 @@ #define EXT3_MOUNT_EXTDEBUG 0x20000 /* Extents debug */ #define EXT3_MOUNT_IOPEN 0x40000 /* Allow access via iopen */ #define EXT3_MOUNT_IOPEN_NOPRIV 0x80000 /* Make iopen world-readable */ +#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 clear_opt @@ -493,6 +494,8 @@ #define EXT3_GOOD_OLD_INODE_SIZE 128 +#define EXT3_S_INRESERVE 01000000 + /* * Feature set definitions */