X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Freiserfs%2Fsuper.c;h=d37dfeaccceba9851eaf42d71b3842b4a82ffaa2;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=1ab82924fba5fa3be574d497c97e3e369d134f5f;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 1ab82924f..d37dfeacc 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -17,17 +17,23 @@ #include #include #include +#include +#include #include #include #include #include #include +#include +#include +#include +#include struct file_system_type reiserfs_fs_type; -const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING; -const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING; -const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING; +static const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING; +static const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING; +static const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING; int is_reiserfs_3_5 (struct reiserfs_super_block * rs) { @@ -59,22 +65,26 @@ static int is_any_reiserfs_magic_string (struct reiserfs_super_block * rs) static int reiserfs_remount (struct super_block * s, int * flags, char * data); static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf); -static void reiserfs_sync_fs (struct super_block * s) +static int reiserfs_sync_fs (struct super_block * s, int wait) { if (!(s->s_flags & MS_RDONLY)) { struct reiserfs_transaction_handle th; reiserfs_write_lock(s); - journal_begin(&th, s, 1); - journal_end_sync(&th, s, 1); - reiserfs_flush_old_commits(s); - s->s_dirt = 0; + if (!journal_begin(&th, s, 1)) + if (!journal_end_sync(&th, s, 1)) + reiserfs_flush_old_commits(s); + s->s_dirt = 0; /* Even if it's not true. + * We'll loop forever in sync_supers otherwise */ reiserfs_write_unlock(s); + } else { + s->s_dirt = 0; } + return 0; } static void reiserfs_write_super(struct super_block *s) { - reiserfs_sync_fs(s); + reiserfs_sync_fs(s, 1); } static void reiserfs_write_super_lockfs (struct super_block * s) @@ -82,21 +92,25 @@ static void reiserfs_write_super_lockfs (struct super_block * s) struct reiserfs_transaction_handle th ; reiserfs_write_lock(s); if (!(s->s_flags & MS_RDONLY)) { - journal_begin(&th, s, 1) ; - reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); - journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); - reiserfs_block_writes(&th) ; - journal_end_sync(&th, s, 1) ; + int err = journal_begin(&th, s, 1) ; + if (err) { + reiserfs_block_writes(&th) ; + } else { + reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); + journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); + reiserfs_block_writes(&th) ; + journal_end_sync(&th, s, 1) ; + } } s->s_dirt = 0; reiserfs_write_unlock(s); } -void reiserfs_unlockfs(struct super_block *s) { +static void reiserfs_unlockfs(struct super_block *s) { reiserfs_allow_writes(s) ; } -extern const struct key MAX_KEY; +extern const struct reiserfs_key MAX_KEY; /* this is used to delete "save link" when there are no items of a @@ -106,29 +120,35 @@ extern const struct key MAX_KEY; protecting unlink is bigger that a key lf "save link" which protects truncate), so there left no items to make truncate completion on */ -static void remove_save_link_only (struct super_block * s, struct key * key, int oid_free) +static int remove_save_link_only (struct super_block * s, struct reiserfs_key * key, int oid_free) { struct reiserfs_transaction_handle th; + int err; /* we are going to do one balancing */ - journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT); + err = journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT); + if (err) + return err; - reiserfs_delete_solid_item (&th, key); + reiserfs_delete_solid_item (&th, NULL, key); if (oid_free) /* removals are protected by direct items */ reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid)); - journal_end (&th, s, JOURNAL_PER_BALANCE_CNT); + return journal_end (&th, s, JOURNAL_PER_BALANCE_CNT); } +#ifdef CONFIG_QUOTA +static int reiserfs_quota_on_mount(struct super_block *, int); +#endif /* look for uncompleted unlinks and truncates and complete them */ -static void finish_unfinished (struct super_block * s) +static int finish_unfinished (struct super_block * s) { INITIALIZE_PATH (path); struct cpu_key max_cpu_key, obj_key; - struct key save_link_key; - int retval; + struct reiserfs_key save_link_key; + int retval = 0; struct item_head * ih; struct buffer_head * bh; int item_pos; @@ -136,19 +156,41 @@ static void finish_unfinished (struct super_block * s) int done; struct inode * inode; int truncate; +#ifdef CONFIG_QUOTA + int i; + int ms_active_set; +#endif /* compose key to look for "save" links */ max_cpu_key.version = KEY_FORMAT_3_5; max_cpu_key.on_disk_key = MAX_KEY; max_cpu_key.key_length = 3; + +#ifdef CONFIG_QUOTA + /* Needed for iput() to work correctly and not trash data */ + if (s->s_flags & MS_ACTIVE) { + ms_active_set = 0; + } else { + ms_active_set = 1; + s->s_flags |= MS_ACTIVE; + } + /* Turn on quotas so that they are updated correctly */ + for (i = 0; i < MAXQUOTAS; i++) { + if (REISERFS_SB(s)->s_qf_names[i]) { + int ret = reiserfs_quota_on_mount(s, i); + if (ret < 0) + reiserfs_warning(s, "reiserfs: cannot turn on journalled quota: error %d", ret); + } + } +#endif done = 0; REISERFS_SB(s)->s_is_unlinked_ok = 1; - while (1) { + while (!retval) { retval = search_item (s, &max_cpu_key, &path); if (retval != ITEM_NOT_FOUND) { - reiserfs_warning ("vs-2140: finish_unfinished: search_by_key returned %d\n", + reiserfs_warning (s, "vs-2140: finish_unfinished: search_by_key returned %d", retval); break; } @@ -156,7 +198,7 @@ static void finish_unfinished (struct super_block * s) bh = get_last_bh (&path); item_pos = get_item_pos (&path); if (item_pos != B_NR_ITEMS (bh)) { - reiserfs_warning ("vs-2060: finish_unfinished: wrong position found\n"); + reiserfs_warning (s, "vs-2060: finish_unfinished: wrong position found"); break; } item_pos --; @@ -185,27 +227,28 @@ static void finish_unfinished (struct super_block * s) if (!inode) { /* the unlink almost completed, it just did not manage to remove "save" link and release objectid */ - reiserfs_warning ("vs-2180: finish_unfinished: iget failed for %K\n", + reiserfs_warning (s, "vs-2180: finish_unfinished: iget failed for %K", &obj_key); - remove_save_link_only (s, &save_link_key, 1); + retval = remove_save_link_only (s, &save_link_key, 1); continue; } if (!truncate && inode->i_nlink) { /* file is not unlinked */ - reiserfs_warning ("vs-2185: finish_unfinished: file %K is not unlinked\n", + reiserfs_warning (s, "vs-2185: finish_unfinished: file %K is not unlinked", &obj_key); - remove_save_link_only (s, &save_link_key, 0); + retval = remove_save_link_only (s, &save_link_key, 0); continue; } + DQUOT_INIT(inode); if (truncate && S_ISDIR (inode->i_mode) ) { /* We got a truncate request for a dir which is impossible. The only imaginable way is to execute unfinished truncate request then boot into old kernel, remove the file and create dir with the same key. */ - reiserfs_warning("green-2101: impossible truncate on a directory %k. Please report\n", INODE_PKEY (inode)); - remove_save_link_only (s, &save_link_key, 0); + reiserfs_warning(s, "green-2101: impossible truncate on a directory %k. Please report", INODE_PKEY (inode)); + retval = remove_save_link_only (s, &save_link_key, 0); truncate = 0; iput (inode); continue; @@ -215,15 +258,16 @@ static void finish_unfinished (struct super_block * s) REISERFS_I(inode) -> i_flags |= i_link_saved_truncate_mask; /* not completed truncate found. New size was committed together with "save" link */ - reiserfs_warning ("Truncating %k to %Ld ..", + reiserfs_info (s, "Truncating %k to %Ld ..", INODE_PKEY (inode), inode->i_size); reiserfs_truncate_file (inode, 0/*don't update modification time*/); - remove_save_link (inode, truncate); + retval = remove_save_link (inode, truncate); } else { REISERFS_I(inode) -> i_flags |= i_link_saved_unlink_mask; /* not completed unlink (rmdir) found */ - reiserfs_warning ("Removing %k..", INODE_PKEY (inode)); + reiserfs_info (s, "Removing %k..", INODE_PKEY (inode)); /* removal gets completed in iput */ + retval = 0; } iput (inode); @@ -232,10 +276,21 @@ static void finish_unfinished (struct super_block * s) } REISERFS_SB(s)->s_is_unlinked_ok = 0; +#ifdef CONFIG_QUOTA + /* Turn quotas off */ + for (i = 0; i < MAXQUOTAS; i++) { + if (sb_dqopt(s)->files[i]) + vfs_quota_off_mount(s, i); + } + if (ms_active_set) + /* Restore the flag back */ + s->s_flags &= ~MS_ACTIVE; +#endif pathrelse (&path); if (done) - reiserfs_warning ("There were %d uncompleted unlinks/truncates. " + reiserfs_info (s, "There were %d uncompleted unlinks/truncates. " "Completed\n", done); + return retval; } /* to protect file being unlinked from getting lost we "safe" link files @@ -251,6 +306,8 @@ void add_save_link (struct reiserfs_transaction_handle * th, struct item_head ih; __u32 link; + BUG_ON (!th->t_trans_id); + /* file can only get one "save link" of each kind */ RFALSE( truncate && ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ), @@ -276,7 +333,7 @@ void add_save_link (struct reiserfs_transaction_handle * th, } else { /* truncate */ if (S_ISDIR (inode->i_mode)) - reiserfs_warning("green-2102: Adding a truncate savelink for a directory %k! Please report\n", INODE_PKEY(inode)); + reiserfs_warning(inode->i_sb, "green-2102: Adding a truncate savelink for a directory %k! Please report", INODE_PKEY(inode)); set_cpu_key_k_offset (&key, 1); set_cpu_key_k_type (&key, TYPE_INDIRECT); @@ -290,8 +347,8 @@ void add_save_link (struct reiserfs_transaction_handle * th, retval = search_item (inode->i_sb, &key, &path); if (retval != ITEM_NOT_FOUND) { if ( retval != -ENOSPC ) - reiserfs_warning ("vs-2100: add_save_link:" - "search_by_key (%K) returned %d\n", &key, retval); + reiserfs_warning (inode->i_sb, "vs-2100: add_save_link:" + "search_by_key (%K) returned %d", &key, retval); pathrelse (&path); return; } @@ -299,11 +356,11 @@ void add_save_link (struct reiserfs_transaction_handle * th, /* body of "save" link */ link = INODE_PKEY (inode)->k_dir_id; - /* put "save" link inot tree */ - retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link); + /* put "save" link inot tree, don't charge quota to anyone */ + retval = reiserfs_insert_item (th, &path, &key, &ih, NULL, (char *)&link); if (retval) { if (retval != -ENOSPC) - reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n", + reiserfs_warning (inode->i_sb, "vs-2120: add_save_link: insert_item returned %d", retval); } else { if( truncate ) @@ -315,14 +372,16 @@ void add_save_link (struct reiserfs_transaction_handle * th, /* this opens transaction unlike add_save_link */ -void remove_save_link (struct inode * inode, int truncate) +int remove_save_link (struct inode * inode, int truncate) { struct reiserfs_transaction_handle th; - struct key key; - + struct reiserfs_key key; + int err; /* we are going to do one balancing only */ - journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); + err = journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); + if (err) + return err; /* setup key of "save" link */ key.k_dir_id = cpu_to_le32 (MAX_KEY_OBJECTID); @@ -342,14 +401,15 @@ void remove_save_link (struct inode * inode, int truncate) ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ) ) || ( !truncate && ( REISERFS_I(inode) -> i_flags & i_link_saved_unlink_mask ) ) ) - reiserfs_delete_solid_item (&th, &key); + /* don't take quota bytes from anywhere */ + reiserfs_delete_solid_item (&th, NULL, &key); if (!truncate) { reiserfs_release_objectid (&th, inode->i_ino); REISERFS_I(inode) -> i_flags &= ~i_link_saved_unlink_mask; } else REISERFS_I(inode) -> i_flags &= ~i_link_saved_truncate_mask; - journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); + return journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); } @@ -357,13 +417,25 @@ static void reiserfs_put_super (struct super_block * s) { int i; struct reiserfs_transaction_handle th ; + th.t_trans_id = 0; + + if (REISERFS_SB(s)->xattr_root) { + d_invalidate (REISERFS_SB(s)->xattr_root); + dput (REISERFS_SB(s)->xattr_root); + } + if (REISERFS_SB(s)->priv_root) { + d_invalidate (REISERFS_SB(s)->priv_root); + dput (REISERFS_SB(s)->priv_root); + } + /* change file system state to current state if it was mounted with read-write permissions */ if (!(s->s_flags & MS_RDONLY)) { - journal_begin(&th, s, 10) ; - reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; - set_sb_umount_state( SB_DISK_SUPER_BLOCK(s), REISERFS_SB(s)->s_mount_state ); - journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); + if (!journal_begin(&th, s, 10)) { + reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; + set_sb_umount_state( SB_DISK_SUPER_BLOCK(s), REISERFS_SB(s)->s_mount_state ); + journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); + } } /* note, journal_release checks for readonly mount, and can decide not @@ -381,12 +453,12 @@ static void reiserfs_put_super (struct super_block * s) print_statistics (s); if (REISERFS_SB(s)->s_kmallocs != 0) { - reiserfs_warning ("vs-2004: reiserfs_put_super: allocated memory left %d\n", + reiserfs_warning (s, "vs-2004: reiserfs_put_super: allocated memory left %d", REISERFS_SB(s)->s_kmallocs); } if (REISERFS_SB(s)->reserved_blocks != 0) { - reiserfs_warning ("green-2005: reiserfs_put_super: reserved blocks left %d\n", + reiserfs_warning (s, "green-2005: reiserfs_put_super: reserved blocks left %d", REISERFS_SB(s)->reserved_blocks); } @@ -422,6 +494,8 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) SLAB_CTOR_CONSTRUCTOR) { INIT_LIST_HEAD(&ei->i_prealloc_list) ; inode_init_once(&ei->vfs_inode); + ei->i_acl_access = NULL; + ei->i_acl_default = NULL; } } @@ -429,7 +503,7 @@ static int init_inodecache(void) { reiserfs_inode_cachep = kmem_cache_create("reiser_inode_cache", sizeof(struct reiserfs_inode_info), - 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, + 0, SLAB_RECLAIM_ACCOUNT, init_once, NULL); if (reiserfs_inode_cachep == NULL) return -ENOMEM; @@ -439,15 +513,16 @@ static int init_inodecache(void) static void destroy_inodecache(void) { if (kmem_cache_destroy(reiserfs_inode_cachep)) - printk(KERN_INFO "reiserfs_inode_cache: not all structures were freed\n"); + reiserfs_warning (NULL, "reiserfs_inode_cache: not all structures were freed"); } /* we don't mark inodes dirty, we just log them */ static void reiserfs_dirty_inode (struct inode * inode) { struct reiserfs_transaction_handle th ; + int err = 0; if (inode->i_sb->s_flags & MS_RDONLY) { - reiserfs_warning("clm-6006: writing inode %lu on readonly FS\n", + reiserfs_warning(inode->i_sb, "clm-6006: writing inode %lu on readonly FS", inode->i_ino) ; return ; } @@ -456,28 +531,97 @@ static void reiserfs_dirty_inode (struct inode * inode) { /* this is really only used for atime updates, so they don't have ** to be included in O_SYNC or fsync */ - journal_begin(&th, inode->i_sb, 1) ; + err = journal_begin(&th, inode->i_sb, 1) ; + if (err) { + reiserfs_write_unlock (inode->i_sb); + return; + } reiserfs_update_sd (&th, inode); journal_end(&th, inode->i_sb, 1) ; reiserfs_write_unlock(inode->i_sb); } -struct super_operations reiserfs_sops = +static void reiserfs_clear_inode (struct inode *inode) +{ + struct posix_acl *acl; + + acl = REISERFS_I(inode)->i_acl_access; + if (acl && !IS_ERR (acl)) + posix_acl_release (acl); + REISERFS_I(inode)->i_acl_access = NULL; + + acl = REISERFS_I(inode)->i_acl_default; + if (acl && !IS_ERR (acl)) + posix_acl_release (acl); + REISERFS_I(inode)->i_acl_default = NULL; +} + +#ifdef CONFIG_QUOTA +static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, size_t, loff_t); +static ssize_t reiserfs_quota_read(struct super_block *, int, char *, size_t, loff_t); +#endif + +static struct super_operations reiserfs_sops = { .alloc_inode = reiserfs_alloc_inode, .destroy_inode = reiserfs_destroy_inode, .write_inode = reiserfs_write_inode, .dirty_inode = reiserfs_dirty_inode, .delete_inode = reiserfs_delete_inode, + .clear_inode = reiserfs_clear_inode, .put_super = reiserfs_put_super, .write_super = reiserfs_write_super, + .sync_fs = reiserfs_sync_fs, .write_super_lockfs = reiserfs_write_super_lockfs, .unlockfs = reiserfs_unlockfs, .statfs = reiserfs_statfs, .remount_fs = reiserfs_remount, +#ifdef CONFIG_QUOTA + .quota_read = reiserfs_quota_read, + .quota_write = reiserfs_quota_write, +#endif +}; + +#ifdef CONFIG_QUOTA +#define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group") +static int reiserfs_dquot_initialize(struct inode *, int); +static int reiserfs_dquot_drop(struct inode *); +static int reiserfs_write_dquot(struct dquot *); +static int reiserfs_acquire_dquot(struct dquot *); +static int reiserfs_release_dquot(struct dquot *); +static int reiserfs_mark_dquot_dirty(struct dquot *); +static int reiserfs_write_info(struct super_block *, int); +static int reiserfs_quota_on(struct super_block *, int, int, char *); + +static struct dquot_operations reiserfs_quota_operations = +{ + .initialize = reiserfs_dquot_initialize, + .drop = reiserfs_dquot_drop, + .alloc_space = dquot_alloc_space, + .alloc_inode = dquot_alloc_inode, + .free_space = dquot_free_space, + .free_inode = dquot_free_inode, + .transfer = dquot_transfer, + .write_dquot = reiserfs_write_dquot, + .acquire_dquot = reiserfs_acquire_dquot, + .release_dquot = reiserfs_release_dquot, + .mark_dirty = reiserfs_mark_dquot_dirty, + .write_info = reiserfs_write_info, }; +static struct quotactl_ops reiserfs_qctl_operations = +{ + .quota_on = reiserfs_quota_on, + .quota_off = vfs_quota_off, + .quota_sync = vfs_quota_sync, + .get_info = vfs_get_dqinfo, + .set_info = vfs_set_dqinfo, + .get_dqblk = vfs_get_dqblk, + .set_dqblk = vfs_set_dqblk, +}; +#endif + static struct export_operations reiserfs_export_ops = { .encode_fh = reiserfs_encode_fh, .decode_fh = reiserfs_decode_fh, @@ -496,6 +640,8 @@ typedef struct { applied BEFORE setmask */ } arg_desc_t; +/* Set this bit in arg_required to allow empty arguments */ +#define REISERFS_OPT_ALLOWEMPTY 31 /* this struct is used in reiserfs_getopt() for describing the set of reiserfs mount options */ @@ -518,6 +664,13 @@ static const arg_desc_t logging_mode[] = { {NULL, 0} }; +/* possible values for -o barrier= */ +static const arg_desc_t barrier_mode[] = { + {"none", 1<option_name; opt ++) { if (!strncmp (p, opt->option_name, strlen (opt->option_name))) { if (bit_flags) { - *bit_flags &= ~opt->clrmask; - *bit_flags |= opt->setmask; + if (opt->clrmask == (1 << REISERFS_UNSUPPORTED_OPT)) + reiserfs_warning (s, "%s not supported.", p); + else + *bit_flags &= ~opt->clrmask; + if (opt->setmask == (1 << REISERFS_UNSUPPORTED_OPT)) + reiserfs_warning (s, "%s not supported.", p); + else + *bit_flags |= opt->setmask; } break; } } if (!opt->option_name) { - printk ("reiserfs_getopt: unknown option \"%s\"\n", p); + reiserfs_warning (s, "unknown mount option \"%s\"", p); return -1; } @@ -603,7 +774,7 @@ static int reiserfs_getopt ( struct super_block * s, char ** cur, opt_desc_t * o switch (*p) { case '=': if (!opt->arg_required) { - printk ("reiserfs_getopt: the option \"%s\" does not require an argument\n", + reiserfs_warning (s, "the option \"%s\" does not require an argument", opt->option_name); return -1; } @@ -611,28 +782,28 @@ static int reiserfs_getopt ( struct super_block * s, char ** cur, opt_desc_t * o case 0: if (opt->arg_required) { - printk ("reiserfs_getopt: the option \"%s\" requires an argument\n", opt->option_name); + reiserfs_warning (s, "the option \"%s\" requires an argument", opt->option_name); return -1; } break; default: - printk ("reiserfs_getopt: head of option \"%s\" is only correct\n", opt->option_name); + reiserfs_warning (s, "head of option \"%s\" is only correct", opt->option_name); return -1; } - + /* move to the argument, or to next option if argument is not required */ p ++; - if ( opt->arg_required && !strlen (p) ) { - /* this catches "option=," */ - printk ("reiserfs_getopt: empty argument for \"%s\"\n", opt->option_name); + if ( opt->arg_required && !(opt->arg_required & (1<option_name); return -1; } if (!opt->values) { /* *=NULLopt_arg contains pointer to argument */ *opt_arg = p; - return opt->arg_required; + return opt->arg_required & ~(1<values */ @@ -646,7 +817,7 @@ static int reiserfs_getopt ( struct super_block * s, char ** cur, opt_desc_t * o } } - printk ("reiserfs_getopt: bad value \"%s\" for option \"%s\"\n", p, opt->option_name); + reiserfs_warning (s, "bad value \"%s\" for option \"%s\"", p, opt->option_name); return -1; } @@ -664,20 +835,43 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st char * arg = NULL; char * pos; opt_desc_t opts[] = { - {"tails", 't', tails, 0, 0}, /* Compatibility stuff, so that -o notail for old setups still work */ - {"notail", 0, 0, 0, (1<= (unsigned int)-1) { + reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg); return 0; } - *commit_max_age = val; + *commit_max_age = (unsigned int)val; } if ( c == 'w' ) { - char *p=0; + char *p=NULL; int val = simple_strtoul (arg, &p, 0); if ( *p != '\0') { - printk ("reiserfs_parse_options: non-numeric value %s for nolargeio option\n", arg); + reiserfs_warning (s, "reiserfs_parse_options: non-numeric value %s for nolargeio option", arg); return 0; } if ( val ) @@ -733,14 +926,68 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st if (c == 'j') { if (arg && *arg && jdev_name) { if ( *jdev_name ) { //Hm, already assigned? - printk("reiserfs_parse_options: journal device was already specified to be %s\n", *jdev_name); + reiserfs_warning (s, "reiserfs_parse_options: journal device was already specified to be %s", *jdev_name); return 0; } *jdev_name = arg; } } + +#ifdef CONFIG_QUOTA + if (c == 'u' || c == 'g') { + int qtype = c == 'u' ? USRQUOTA : GRPQUOTA; + + if (sb_any_quota_enabled(s)) { + reiserfs_warning(s, "reiserfs_parse_options: cannot change journalled quota options when quota turned on."); + return 0; + } + if (*arg) { /* Some filename specified? */ + if (REISERFS_SB(s)->s_qf_names[qtype] && strcmp(REISERFS_SB(s)->s_qf_names[qtype], arg)) { + reiserfs_warning(s, "reiserfs_parse_options: %s quota file already specified.", QTYPE2NAME(qtype)); + return 0; + } + if (strchr(arg, '/')) { + reiserfs_warning(s, "reiserfs_parse_options: quotafile must be on filesystem root."); + return 0; + } + REISERFS_SB(s)->s_qf_names[qtype] = kmalloc(strlen(arg)+1, GFP_KERNEL); + if (!REISERFS_SB(s)->s_qf_names[qtype]) { + reiserfs_warning(s, "reiserfs_parse_options: not enough memory for storing quotafile name."); + return 0; + } + strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg); + } + else { + if (REISERFS_SB(s)->s_qf_names[qtype]) { + kfree(REISERFS_SB(s)->s_qf_names[qtype]); + REISERFS_SB(s)->s_qf_names[qtype] = NULL; + } + } + } + if (c == 'f') { + if (!strcmp(arg, "vfsold")) + REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_OLD; + else if (!strcmp(arg, "vfsv0")) + REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_V0; + else { + reiserfs_warning(s, "reiserfs_parse_options: unknown quota format specified."); + return 0; + } + } +#else + if (c == 'u' || c == 'g' || c == 'f') { + reiserfs_warning(s, "reiserfs_parse_options: journalled quota options not supported."); + return 0; + } +#endif } +#ifdef CONFIG_QUOTA + if (!REISERFS_SB(s)->s_jquota_fmt && (REISERFS_SB(s)->s_qf_names[USRQUOTA] || REISERFS_SB(s)->s_qf_names[GRPQUOTA])) { + reiserfs_warning(s, "reiserfs_parse_options: journalled quota format not specified."); + return 0; + } +#endif return 1; } @@ -756,21 +1003,38 @@ static void handle_data_mode(struct super_block *s, unsigned long mount_options) if (mount_options & (1 << REISERFS_DATA_LOG)) { if (!reiserfs_data_log(s)) { switch_data_mode(s, REISERFS_DATA_LOG); - printk("reiserfs: switching to journaled data mode\n"); + reiserfs_info (s, "switching to journaled data mode\n"); } } else if (mount_options & (1 << REISERFS_DATA_ORDERED)) { if (!reiserfs_data_ordered(s)) { switch_data_mode(s, REISERFS_DATA_ORDERED); - printk("reiserfs: switching to ordered data mode\n"); + reiserfs_info (s, "switching to ordered data mode\n"); } } else if (mount_options & (1 << REISERFS_DATA_WRITEBACK)) { if (!reiserfs_data_writeback(s)) { switch_data_mode(s, REISERFS_DATA_WRITEBACK); - printk("reiserfs: switching to writeback data mode\n"); + reiserfs_info (s, "switching to writeback data mode\n"); } } } +static void handle_barrier_mode(struct super_block *s, unsigned long bits) { + int flush = (1 << REISERFS_BARRIER_FLUSH); + int none = (1 << REISERFS_BARRIER_NONE); + int all_barrier = flush | none; + + if (bits & all_barrier) { + REISERFS_SB(s)->s_mount_opt &= ~all_barrier; + if (bits & flush) { + REISERFS_SB(s)->s_mount_opt |= flush; + printk("reiserfs: enabling write barrier flush mode\n"); + } else if (bits & none) { + REISERFS_SB(s)->s_mount_opt |= none; + printk("reiserfs: write barriers turned off\n"); + } + } +} + static void handle_attrs( struct super_block *s ) { struct reiserfs_super_block * rs; @@ -778,12 +1042,12 @@ static void handle_attrs( struct super_block *s ) if( reiserfs_attrs( s ) ) { rs = SB_DISK_SUPER_BLOCK (s); if( old_format_only(s) ) { - reiserfs_warning( "reiserfs: cannot support attributes on 3.5.x disk format\n" ); + reiserfs_warning(s, "reiserfs: cannot support attributes on 3.5.x disk format" ); REISERFS_SB(s) -> s_mount_opt &= ~ ( 1 << REISERFS_ATTRS ); return; } if( !( le32_to_cpu( rs -> s_flags ) & reiserfs_attrs_cleared ) ) { - reiserfs_warning( "reiserfs: cannot support attributes until flag is set in super-block\n" ); + reiserfs_warning(s, "reiserfs: cannot support attributes until flag is set in super-block" ); REISERFS_SB(s) -> s_mount_opt &= ~ ( 1 << REISERFS_ATTRS ); } } @@ -796,12 +1060,25 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a unsigned long blocks; unsigned long mount_options = REISERFS_SB(s)->s_mount_opt; unsigned long safe_mask = 0; - unsigned int commit_max_age = 0; + unsigned int commit_max_age = (unsigned int)-1; + struct reiserfs_journal *journal = SB_JOURNAL(s); + int err; +#ifdef CONFIG_QUOTA + int i; +#endif rs = SB_DISK_SUPER_BLOCK (s); - if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL, &commit_max_age)) + if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL, &commit_max_age)) { +#ifdef CONFIG_QUOTA + for (i = 0; i < MAXQUOTAS; i++) + if (REISERFS_SB(s)->s_qf_names[i]) { + kfree(REISERFS_SB(s)->s_qf_names[i]); + REISERFS_SB(s)->s_qf_names[i] = NULL; + } +#endif return -EINVAL; + } handle_attrs(s); @@ -813,20 +1090,27 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a safe_mask |= 1 << REISERFS_HASHED_RELOCATION; safe_mask |= 1 << REISERFS_TEST4; safe_mask |= 1 << REISERFS_ATTRS; + safe_mask |= 1 << REISERFS_XATTRS_USER; + safe_mask |= 1 << REISERFS_POSIXACL; + safe_mask |= 1 << REISERFS_BARRIER_FLUSH; + safe_mask |= 1 << REISERFS_BARRIER_NONE; + safe_mask |= 1 << REISERFS_ERROR_RO; + safe_mask |= 1 << REISERFS_ERROR_CONTINUE; + safe_mask |= 1 << REISERFS_ERROR_PANIC; /* Update the bitmask, taking care to keep * the bits we're not allowed to change here */ REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) | (mount_options & safe_mask); - if(commit_max_age != 0) { - SB_JOURNAL_MAX_COMMIT_AGE(s) = commit_max_age; - SB_JOURNAL_MAX_TRANS_AGE(s) = commit_max_age; + if(commit_max_age != 0 && commit_max_age != (unsigned int)-1) { + journal->j_max_commit_age = commit_max_age; + journal->j_max_trans_age = commit_max_age; } - else + else if(commit_max_age == 0) { /* 0 means restore defaults. */ - SB_JOURNAL_MAX_COMMIT_AGE(s) = SB_JOURNAL_DEFAULT_MAX_COMMIT_AGE(s); - SB_JOURNAL_MAX_TRANS_AGE(s) = JOURNAL_MAX_TRANS_AGE; + journal->j_max_commit_age = journal->j_default_max_commit_age; + journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE; } if(blocks) { @@ -836,6 +1120,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a } if (*mount_flags & MS_RDONLY) { + reiserfs_xattr_init (s, *mount_flags); /* remount read-only */ if (s->s_flags & MS_RDONLY) /* it is read-only already */ @@ -845,20 +1130,31 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a return 0; } - journal_begin(&th, s, 10) ; + err = journal_begin(&th, s, 10) ; + if (err) + return err; + /* Mounting a rw partition read-only. */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; set_sb_umount_state( rs, REISERFS_SB(s)->s_mount_state ); journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); } else { /* remount read-write */ - if (!(s->s_flags & MS_RDONLY)) + if (!(s->s_flags & MS_RDONLY)) { + reiserfs_xattr_init (s, *mount_flags); return 0; /* We are read-write already */ + } + + if (reiserfs_is_journal_aborted (journal)) + return journal->j_errno; handle_data_mode(s, mount_options); + handle_barrier_mode(s, mount_options); REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ; s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */ - journal_begin(&th, s, 10) ; + err = journal_begin(&th, s, 10) ; + if (err) + return err; /* Mount a partition which is read-only, read-write */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; @@ -871,11 +1167,15 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a } /* this will force a full flush of all journal lists */ SB_JOURNAL(s)->j_must_wait = 1 ; - journal_end(&th, s, 10) ; + err = journal_end(&th, s, 10) ; + if (err) + return err; s->s_dirt = 0; - if (!( *mount_flags & MS_RDONLY ) ) + if (!( *mount_flags & MS_RDONLY ) ) { finish_unfinished( s ); + reiserfs_xattr_init (s, *mount_flags); + } return 0; } @@ -926,7 +1226,7 @@ static void load_bitmap_info_data (struct super_block *sb, #ifdef CONFIG_REISERFS_CHECK // This outputs a lot of unneded info on big FSes -// reiserfs_warning ("bitmap loaded from block %d: %d free blocks\n", +// reiserfs_warning ("bitmap loaded from block %d: %d free blocks", // bi->bh->b_blocknr, bi->free_count); #endif } @@ -948,8 +1248,8 @@ static int read_bitmaps (struct super_block * s) for (i = 0; i < SB_BMAP_NR(s); i++) { wait_on_buffer(SB_AP_BITMAP (s)[i].bh); if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) { - reiserfs_warning("sh-2029: reiserfs read_bitmaps: " - "bitmap block (#%lu) reading failed\n", + reiserfs_warning(s,"sh-2029: reiserfs read_bitmaps: " + "bitmap block (#%lu) reading failed", SB_AP_BITMAP(s)[i].bh->b_blocknr); for (i = 0; i < SB_BMAP_NR(s); i++) brelse(SB_AP_BITMAP(s)[i].bh); @@ -985,24 +1285,6 @@ static int read_old_bitmaps (struct super_block * s) return 0; } -void check_bitmap (struct super_block * s) -{ - int i = 0; - int free = 0; - char * buf; - - while (i < SB_BLOCK_COUNT (s)) { - buf = SB_AP_BITMAP (s)[i / (s->s_blocksize * 8)].bh->b_data; - if (!reiserfs_test_le_bit (i % (s->s_blocksize * 8), buf)) - free ++; - i ++; - } - - if (free != SB_FREE_BLOCKS (s)) - reiserfs_warning ("vs-4000: check_bitmap: %d free blocks, must be %d\n", - free, SB_FREE_BLOCKS (s)); -} - static int read_super_block (struct super_block * s, int offset) { struct buffer_head * bh; @@ -1012,8 +1294,8 @@ static int read_super_block (struct super_block * s, int offset) bh = sb_bread (s, offset / s->s_blocksize); if (!bh) { - printk ("sh-2006: read_super_block: " - "bread failed (dev %s, block %lu, size %lu)\n", + reiserfs_warning (s, "sh-2006: read_super_block: " + "bread failed (dev %s, block %lu, size %lu)", reiserfs_bdevname (s), offset / s->s_blocksize, s->s_blocksize); return 1; } @@ -1033,7 +1315,7 @@ static int read_super_block (struct super_block * s, int offset) bh = sb_bread (s, offset / s->s_blocksize); if (!bh) { - printk("sh-2007: read_super_block: " + reiserfs_warning (s, "sh-2007: read_super_block: " "bread failed (dev %s, block %lu, size %lu)\n", reiserfs_bdevname (s), offset / s->s_blocksize, s->s_blocksize); return 1; @@ -1041,7 +1323,7 @@ static int read_super_block (struct super_block * s, int offset) rs = (struct reiserfs_super_block *)bh->b_data; if (sb_blocksize(rs) != s->s_blocksize) { - printk ("sh-2011: read_super_block: " + reiserfs_warning (s, "sh-2011: read_super_block: " "can't find a reiserfs filesystem on (dev %s, block %Lu, size %lu)\n", reiserfs_bdevname (s), (unsigned long long)bh->b_blocknr, s->s_blocksize); brelse (bh); @@ -1050,9 +1332,9 @@ static int read_super_block (struct super_block * s, int offset) if ( rs->s_v1.s_root_block == -1 ) { brelse(bh) ; - printk("dev %s: Unfinished reiserfsck --rebuild-tree run detected. Please run\n" + reiserfs_warning (s, "Unfinished reiserfsck --rebuild-tree run detected. Please run\n" "reiserfsck --rebuild-tree and wait for a completion. If that fails\n" - "get newer reiserfsprogs package\n", reiserfs_bdevname (s)); + "get newer reiserfsprogs package"); return 1; } @@ -1063,25 +1345,30 @@ static int read_super_block (struct super_block * s, int offset) /* magic is of non-standard journal filesystem, look at s_version to find which format is in use */ if (sb_version(rs) == REISERFS_VERSION_2) - printk ("read_super_block: found reiserfs format \"3.6\" " - "with non-standard journal\n"); + reiserfs_warning (s, "read_super_block: found reiserfs format \"3.6\"" + " with non-standard journal"); else if (sb_version(rs) == REISERFS_VERSION_1) - printk ("read_super_block: found reiserfs format \"3.5\" " - "with non-standard journal\n"); + reiserfs_warning (s, "read_super_block: found reiserfs format \"3.5\"" + " with non-standard journal"); else { - printk ("sh-2012: read_super_block: found unknown format \"%u\" " - "of reiserfs with non-standard magic\n", sb_version(rs)); + reiserfs_warning (s, "sh-2012: read_super_block: found unknown " + "format \"%u\" of reiserfs with non-standard magic", + sb_version(rs)); return 1; } } else /* s_version of standard format may contain incorrect information, so we just look at the magic string */ - printk ("found reiserfs format \"%s\" with standard journal\n", + reiserfs_info (s, "found reiserfs format \"%s\" with standard journal\n", is_reiserfs_3_5 (rs) ? "3.5" : "3.6"); s->s_op = &reiserfs_sops; s->s_export_op = &reiserfs_export_ops; +#ifdef CONFIG_QUOTA + s->s_qcop = &reiserfs_qctl_operations; + s->dq_op = &reiserfs_quota_operations; +#endif /* new format is limited by the 32 bit wide i_blocks field, want to ** be one full block below that. @@ -1098,7 +1385,7 @@ static int reread_meta_blocks(struct super_block *s) { ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s))) ; wait_on_buffer(SB_BUFFER_WITH_SB(s)) ; if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) { - printk("reread_meta_blocks, error reading the super\n") ; + reiserfs_warning (s, "reread_meta_blocks, error reading the super") ; return 1 ; } @@ -1106,7 +1393,7 @@ static int reread_meta_blocks(struct super_block *s) { ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh)) ; wait_on_buffer(SB_AP_BITMAP(s)[i].bh) ; if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) { - printk("reread_meta_blocks, error reading bitmap block number %d at %llu\n", + reiserfs_warning (s, "reread_meta_blocks, error reading bitmap block number %d at %llu", i, (unsigned long long)SB_AP_BITMAP(s)[i].bh->b_blocknr) ; return 1 ; } @@ -1125,7 +1412,7 @@ static int reread_meta_blocks(struct super_block *s) { // FIXME: we look for only one name in a directory. If tea and yura // bith have the same value - we ask user to send report to the // mailing list -__u32 find_hash_out (struct super_block * s) +static __u32 find_hash_out (struct super_block * s) { int retval; struct inode * inode; @@ -1153,8 +1440,8 @@ __u32 find_hash_out (struct super_block * s) if (reiserfs_rupasov_hash(s)) { hash = YURA_HASH ; } - reiserfs_warning("reiserfs: FS seems to be empty, autodetect " - "is using the default hash\n"); + reiserfs_warning(s,"FS seems to be empty, autodetect " + "is using the default hash"); break; } r5hash=GET_HASH_VALUE (r5_hash (de.de_name, de.de_namelen)); @@ -1163,9 +1450,9 @@ __u32 find_hash_out (struct super_block * s) if ( ( (teahash == r5hash) && (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) ) || ( (teahash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))) ) || ( (r5hash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))) ) ) { - reiserfs_warning("reiserfs: Unable to automatically detect hash" - "function for device %s\n" - "please mount with -o hash={tea,rupasov,r5}\n", reiserfs_bdevname (s)); + reiserfs_warning(s,"Unable to automatically detect hash function. " + "Please mount with -o hash={tea,rupasov,r5}", + reiserfs_bdevname (s)); hash = UNSET_HASH; break; } @@ -1176,8 +1463,7 @@ __u32 find_hash_out (struct super_block * s) else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == r5hash) hash = R5_HASH; else { - reiserfs_warning("reiserfs: Unrecognised hash function for " - "device %s\n", reiserfs_bdevname (s)); + reiserfs_warning (s,"Unrecognised hash function"); hash = UNSET_HASH; } } while (0); @@ -1205,16 +1491,16 @@ static int what_hash (struct super_block * s) ** mount options */ if (reiserfs_rupasov_hash(s) && code != YURA_HASH) { - printk("REISERFS: Error, %s hash detected, " - "unable to force rupasov hash\n", reiserfs_hashname(code)) ; + reiserfs_warning (s, "Error, %s hash detected, " + "unable to force rupasov hash", reiserfs_hashname(code)) ; code = UNSET_HASH ; } else if (reiserfs_tea_hash(s) && code != TEA_HASH) { - printk("REISERFS: Error, %s hash detected, " - "unable to force tea hash\n", reiserfs_hashname(code)) ; + reiserfs_warning (s, "Error, %s hash detected, " + "unable to force tea hash", reiserfs_hashname(code)) ; code = UNSET_HASH ; } else if (reiserfs_r5_hash(s) && code != R5_HASH) { - printk("REISERFS: Error, %s hash detected, " - "unable to force r5 hash\n", reiserfs_hashname(code)) ; + reiserfs_warning (s, "Error, %s hash detected, " + "unable to force r5 hash", reiserfs_hashname(code)) ; code = UNSET_HASH ; } } else { @@ -1244,20 +1530,20 @@ static hashf_t hash_function (struct super_block * s) { switch (what_hash (s)) { case TEA_HASH: - reiserfs_warning ("Using tea hash to sort names\n"); + reiserfs_info (s, "Using tea hash to sort names\n"); return keyed_hash; case YURA_HASH: - reiserfs_warning ("Using rupasov hash to sort names\n"); + reiserfs_info (s, "Using rupasov hash to sort names\n"); return yura_hash; case R5_HASH: - reiserfs_warning ("Using r5 hash to sort names\n"); + reiserfs_info (s, "Using r5 hash to sort names\n"); return r5_hash; } return NULL; } // this is used to set up correct value for old partitions -int function2code (hashf_t func) +static int function2code (hashf_t func) { if (func == keyed_hash) return TEA_HASH; @@ -1271,9 +1557,9 @@ int function2code (hashf_t func) return 0; } -#define SPRINTK(silent, ...) \ +#define SWARN(silent, s, ...) \ if (!(silent)) \ - printk(__VA_ARGS__) + reiserfs_warning (s, __VA_ARGS__) static int reiserfs_fill_super (struct super_block * s, void * data, int silent) { @@ -1282,7 +1568,7 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) struct reiserfs_transaction_handle th ; int old_format = 0; unsigned long blocks; - unsigned int commit_max_age = 0; + unsigned int commit_max_age = 0; int jinit_done = 0 ; struct reiserfs_iget_args args ; struct reiserfs_super_block * rs; @@ -1297,14 +1583,19 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) } s->s_fs_info = sbi; memset (sbi, 0, sizeof (struct reiserfs_sb_info)); - /* Set default values for options: non-aggressive tails */ - REISERFS_SB(s)->s_mount_opt = ( 1 << REISERFS_SMALLTAIL ); - /* default block allocator option: skip_busy */ - REISERFS_SB(s)->s_alloc_options.bits = ( 1 << 5); - /* If file grew past 4 blocks, start preallocation blocks for it. */ - REISERFS_SB(s)->s_alloc_options.preallocmin = 4; + /* Set default values for options: non-aggressive tails, RO on errors */ + REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_SMALLTAIL); + REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ERROR_RO); + /* no preallocation minimum, be smart in + reiserfs_file_write instead */ + REISERFS_SB(s)->s_alloc_options.preallocmin = 0; /* Preallocate by 16 blocks (17-1) at once */ REISERFS_SB(s)->s_alloc_options.preallocsize = 17; + /* Initialize the rwsem for xattr dir */ + init_rwsem(&REISERFS_SB(s)->xattr_dir_sem); + + /* setup default block allocator options */ + reiserfs_init_alloc_options(s); jdev_name = NULL; if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name, &commit_max_age) == 0) { @@ -1312,7 +1603,8 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) } if (blocks) { - SPRINTK(silent, "jmacd-7: reiserfs_fill_super: resize option for remount only\n"); + SWARN (silent, s, "jmacd-7: reiserfs_fill_super: resize option " + "for remount only"); goto error; } @@ -1321,7 +1613,7 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) old_format = 1; /* try new format (64-th 1k block), which can contain reiserfs super block */ else if (read_super_block (s, REISERFS_DISK_OFFSET_IN_BYTES)) { - SPRINTK(silent, "sh-2021: reiserfs_fill_super: can not find reiserfs on %s\n", reiserfs_bdevname (s)); + SWARN(silent, s, "sh-2021: reiserfs_fill_super: can not find reiserfs on %s", reiserfs_bdevname (s)); goto error; } @@ -1330,9 +1622,9 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) smaller than the filesystem. If the check fails then abort and scream, because bad stuff will happen otherwise. */ if ( s->s_bdev && s->s_bdev->bd_inode && i_size_read(s->s_bdev->bd_inode) < sb_block_count(rs)*sb_blocksize(rs)) { - SPRINTK(silent, "Filesystem on %s cannot be mounted because it is bigger than the device\n", reiserfs_bdevname(s)); - SPRINTK(silent, "You may need to run fsck or increase size of your LVM partition\n"); - SPRINTK(silent, "Or may be you forgot to reboot after fdisk when it told you to\n"); + SWARN (silent, s, "Filesystem on %s cannot be mounted because it is bigger than the device", reiserfs_bdevname(s)); + SWARN(silent, s, "You may need to run fsck or increase size of your LVM partition"); + SWARN(silent, s, "Or may be you forgot to reboot after fdisk when it told you to"); goto error; } @@ -1340,12 +1632,12 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) sbi->s_mount_state = REISERFS_VALID_FS ; if (old_format ? read_old_bitmaps(s) : read_bitmaps(s)) { - SPRINTK(silent, "jmacd-8: reiserfs_fill_super: unable to read bitmap\n"); + SWARN(silent, s, "jmacd-8: reiserfs_fill_super: unable to read bitmap"); goto error; } #ifdef CONFIG_REISERFS_CHECK - SPRINTK(silent, "reiserfs:warning: CONFIG_REISERFS_CHECK is set ON\n"); - SPRINTK(silent, "reiserfs:warning: - it is slow mode for debugging.\n"); + SWARN (silent, s, "CONFIG_REISERFS_CHECK is set ON"); + SWARN (silent, s, "- it is slow mode for debugging."); #endif /* make data=ordered the default */ @@ -1356,16 +1648,19 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) } if (reiserfs_data_log(s)) { - printk("reiserfs: using journaled data mode\n"); + reiserfs_info (s, "using journaled data mode\n"); } else if (reiserfs_data_ordered(s)) { - printk("reiserfs: using ordered data mode\n"); + reiserfs_info (s, "using ordered data mode\n"); } else { - printk("reiserfs: using writeback data mode\n"); + reiserfs_info (s, "using writeback data mode\n"); + } + if (reiserfs_barrier_flush(s)) { + printk("reiserfs: using flush barriers\n"); } // set_device_ro(s->s_dev, 1) ; if( journal_init(s, jdev_name, old_format, commit_max_age) ) { - SPRINTK(silent, "sh-2022: reiserfs_fill_super: unable to initialize journal space\n") ; + SWARN(silent, s, "sh-2022: reiserfs_fill_super: unable to initialize journal space") ; goto error ; } else { jinit_done = 1 ; /* once this is set, journal_release must be called @@ -1373,7 +1668,7 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) */ } if (reread_meta_blocks(s)) { - SPRINTK(silent, "jmacd-9: reiserfs_fill_super: unable to reread meta blocks after journal init\n") ; + SWARN(silent, s, "jmacd-9: reiserfs_fill_super: unable to reread meta blocks after journal init") ; goto error ; } @@ -1381,14 +1676,14 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) goto error; if (bdev_read_only(s->s_bdev) && !(s->s_flags & MS_RDONLY)) { - SPRINTK(silent, "clm-7000: Detected readonly device, marking FS readonly\n") ; + SWARN(silent, s, "clm-7000: Detected readonly device, marking FS readonly") ; s->s_flags |= MS_RDONLY ; } args.objectid = REISERFS_ROOT_OBJECTID ; args.dirid = REISERFS_ROOT_PARENT_OBJECTID ; root_inode = iget5_locked (s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor, reiserfs_init_locked_inode, (void *)(&args)); if (!root_inode) { - SPRINTK(silent, "jmacd-10: reiserfs_fill_super: get root inode failed\n"); + SWARN(silent, s, "jmacd-10: reiserfs_fill_super: get root inode failed"); goto error; } @@ -1418,7 +1713,12 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) if (!(s->s_flags & MS_RDONLY)) { - journal_begin(&th, s, 1) ; + errval = journal_begin(&th, s, 1) ; + if (errval) { + dput (s->s_root); + s->s_root = NULL; + goto error; + } reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; set_sb_umount_state( rs, REISERFS_ERROR_FS ); @@ -1430,7 +1730,7 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) if (convert_reiserfs (s)) { /* and -o conv is given */ if(!silent) - reiserfs_warning ("reiserfs: converting 3.5 filesystem to the 3.6 format\n") ; + reiserfs_info (s,"converting 3.5 filesystem to the 3.6 format") ; if (is_reiserfs_3_5 (rs)) /* put magic string of 3.6 format. 2.2 will not be able to @@ -1443,18 +1743,35 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) set_bit(REISERFS_3_6, &(sbi->s_properties)); clear_bit(REISERFS_3_5, &(sbi->s_properties)); } else if (!silent){ - reiserfs_warning("reiserfs: using 3.5.x disk format\n") ; + reiserfs_info (s, "using 3.5.x disk format\n") ; } } journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); - journal_end(&th, s, 1) ; - + errval = journal_end(&th, s, 1) ; + if (errval) { + dput (s->s_root); + s->s_root = NULL; + goto error; + } + + if ((errval = reiserfs_xattr_init (s, s->s_flags))) { + dput (s->s_root); + s->s_root = NULL; + goto error; + } + /* look for files which were to be removed in previous session */ finish_unfinished (s); } else { if ( old_format_only(s) && !silent) { - reiserfs_warning("reiserfs: using 3.5.x disk format\n") ; + reiserfs_info (s, "using 3.5.x disk format\n") ; + } + + if ((errval = reiserfs_xattr_init (s, s->s_flags))) { + dput (s->s_root); + s->s_root = NULL; + goto error; } } // mark hash in super block: it could be unset. overwrite should be ok @@ -1465,7 +1782,7 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) reiserfs_proc_info_init( s ); init_waitqueue_head (&(sbi->s_wait)); - sbi->bitmap_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&sbi->bitmap_lock); return (0); @@ -1483,7 +1800,12 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) } if (SB_BUFFER_WITH_SB (s)) brelse(SB_BUFFER_WITH_SB (s)); - +#ifdef CONFIG_QUOTA + for (j = 0; j < MAXQUOTAS; j++) { + if (sbi->s_qf_names[j]) + kfree(sbi->s_qf_names[j]); + } +#endif if (sbi != NULL) { kfree(sbi); } @@ -1507,6 +1829,262 @@ static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf) return 0; } +#ifdef CONFIG_QUOTA +static int reiserfs_dquot_initialize(struct inode *inode, int type) +{ + struct reiserfs_transaction_handle th; + int ret; + + /* We may create quota structure so we need to reserve enough blocks */ + reiserfs_write_lock(inode->i_sb); + journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); + ret = dquot_initialize(inode, type); + journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); + reiserfs_write_unlock(inode->i_sb); + return ret; +} + +static int reiserfs_dquot_drop(struct inode *inode) +{ + struct reiserfs_transaction_handle th; + int ret; + + /* We may delete quota structure so we need to reserve enough blocks */ + reiserfs_write_lock(inode->i_sb); + journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); + ret = dquot_drop(inode); + journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); + reiserfs_write_unlock(inode->i_sb); + return ret; +} + +static int reiserfs_write_dquot(struct dquot *dquot) +{ + struct reiserfs_transaction_handle th; + int ret; + + reiserfs_write_lock(dquot->dq_sb); + journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS); + ret = dquot_commit(dquot); + journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS); + reiserfs_write_unlock(dquot->dq_sb); + return ret; +} + +static int reiserfs_acquire_dquot(struct dquot *dquot) +{ + struct reiserfs_transaction_handle th; + int ret; + + reiserfs_write_lock(dquot->dq_sb); + journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); + ret = dquot_acquire(dquot); + journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); + reiserfs_write_unlock(dquot->dq_sb); + return ret; +} + +static int reiserfs_release_dquot(struct dquot *dquot) +{ + struct reiserfs_transaction_handle th; + int ret; + + reiserfs_write_lock(dquot->dq_sb); + journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); + ret = dquot_release(dquot); + journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); + reiserfs_write_unlock(dquot->dq_sb); + return ret; +} + +static int reiserfs_mark_dquot_dirty(struct dquot *dquot) +{ + /* Are we journalling quotas? */ + if (REISERFS_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || + REISERFS_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { + dquot_mark_dquot_dirty(dquot); + return reiserfs_write_dquot(dquot); + } + else + return dquot_mark_dquot_dirty(dquot); +} + +static int reiserfs_write_info(struct super_block *sb, int type) +{ + struct reiserfs_transaction_handle th; + int ret; + + /* Data block + inode block */ + reiserfs_write_lock(sb); + journal_begin(&th, sb, 2); + ret = dquot_commit_info(sb, type); + journal_end(&th, sb, 2); + reiserfs_write_unlock(sb); + return ret; +} + +/* + * Turn on quotas during mount time - we need to find + * the quota file and such... + */ +static int reiserfs_quota_on_mount(struct super_block *sb, int type) +{ + int err; + struct dentry *dentry; + struct qstr name = { .name = REISERFS_SB(sb)->s_qf_names[type], + .hash = 0, + .len = strlen(REISERFS_SB(sb)->s_qf_names[type])}; + + dentry = lookup_hash(&name, sb->s_root); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + err = vfs_quota_on_mount(type, REISERFS_SB(sb)->s_jquota_fmt, dentry); + /* Now invalidate and put the dentry - quota got its own reference + * to inode and dentry has at least wrong hash so we had better + * throw it away */ + d_invalidate(dentry); + dput(dentry); + return err; +} + +/* + * Standard function to be called on quota_on + */ +static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, char *path) +{ + int err; + struct nameidata nd; + + err = path_lookup(path, LOOKUP_FOLLOW, &nd); + if (err) + return err; + /* Quotafile not on the same filesystem? */ + if (nd.mnt->mnt_sb != sb) { + path_release(&nd); + return -EXDEV; + } + /* We must not pack tails for quota files on reiserfs for quota IO to work */ + if (!REISERFS_I(nd.dentry->d_inode)->i_flags & i_nopack_mask) { + reiserfs_warning(sb, "reiserfs: Quota file must have tail packing disabled."); + path_release(&nd); + return -EINVAL; + } + /* Not journalling quota? No more tests needed... */ + if (!REISERFS_SB(sb)->s_qf_names[USRQUOTA] && + !REISERFS_SB(sb)->s_qf_names[GRPQUOTA]) { + path_release(&nd); + return vfs_quota_on(sb, type, format_id, path); + } + /* Quotafile not of fs root? */ + if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode) + reiserfs_warning(sb, "reiserfs: Quota file not on filesystem root. " + "Journalled quota will not work."); + path_release(&nd); + return vfs_quota_on(sb, type, format_id, path); +} + +/* Read data from quotafile - avoid pagecache and such because we cannot afford + * acquiring the locks... As quota files are never truncated and quota code + * itself serializes the operations (and noone else should touch the files) + * we don't have to be afraid of races */ +static ssize_t reiserfs_quota_read(struct super_block *sb, int type, char *data, + size_t len, loff_t off) +{ + struct inode *inode = sb_dqopt(sb)->files[type]; + unsigned long blk = off >> sb->s_blocksize_bits; + int err = 0, offset = off & (sb->s_blocksize - 1), tocopy; + size_t toread; + struct buffer_head tmp_bh, *bh; + loff_t i_size = i_size_read(inode); + + if (off > i_size) + return 0; + if (off+len > i_size) + len = i_size-off; + toread = len; + while (toread > 0) { + tocopy = sb->s_blocksize - offset < toread ? sb->s_blocksize - offset : toread; + tmp_bh.b_state = 0; + /* Quota files are without tails so we can safely use this function */ + reiserfs_write_lock(sb); + err = reiserfs_get_block(inode, blk, &tmp_bh, 0); + reiserfs_write_unlock(sb); + if (err) + return err; + if (!buffer_mapped(&tmp_bh)) /* A hole? */ + memset(data, 0, tocopy); + else { + bh = sb_bread(sb, tmp_bh.b_blocknr); + if (!bh) + return -EIO; + memcpy(data, bh->b_data+offset, tocopy); + brelse(bh); + } + offset = 0; + toread -= tocopy; + data += tocopy; + blk++; + } + return len; +} + +/* Write to quotafile (we know the transaction is already started and has + * enough credits) */ +static ssize_t reiserfs_quota_write(struct super_block *sb, int type, + const char *data, size_t len, loff_t off) +{ + struct inode *inode = sb_dqopt(sb)->files[type]; + unsigned long blk = off >> sb->s_blocksize_bits; + int err = 0, offset = off & (sb->s_blocksize - 1), tocopy; + int journal_quota = REISERFS_SB(sb)->s_qf_names[type] != NULL; + size_t towrite = len; + struct buffer_head tmp_bh, *bh; + + down(&inode->i_sem); + while (towrite > 0) { + tocopy = sb->s_blocksize - offset < towrite ? + sb->s_blocksize - offset : towrite; + tmp_bh.b_state = 0; + err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE); + if (err) + goto out; + if (offset || tocopy != sb->s_blocksize) + bh = sb_bread(sb, tmp_bh.b_blocknr); + else + bh = sb_getblk(sb, tmp_bh.b_blocknr); + if (!bh) { + err = -EIO; + goto out; + } + lock_buffer(bh); + memcpy(bh->b_data+offset, data, tocopy); + flush_dcache_page(bh->b_page); + set_buffer_uptodate(bh); + unlock_buffer(bh); + reiserfs_prepare_for_journal(sb, bh, 1); + journal_mark_dirty(current->journal_info, sb, bh); + if (!journal_quota) + reiserfs_add_ordered_list(inode, bh); + brelse(bh); + offset = 0; + towrite -= tocopy; + data += tocopy; + blk++; + } +out: + if (len == towrite) + return err; + if (inode->i_size < off+len-towrite) + i_size_write(inode, off+len-towrite); + inode->i_version++; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + up(&inode->i_sem); + return len - towrite; +} + +#endif + static struct super_block* get_super_block (struct file_system_type *fs_type, int flags, const char *dev_name, void *data) @@ -1523,6 +2101,9 @@ init_reiserfs_fs ( void ) return ret; } + if ((ret = reiserfs_xattr_register_handlers ())) + goto failed_reiserfs_xattr_register_handlers; + reiserfs_proc_info_global_init (); reiserfs_proc_register_global ("version", reiserfs_global_version_in_proc); @@ -1532,6 +2113,9 @@ init_reiserfs_fs ( void ) return 0; } + reiserfs_xattr_unregister_handlers (); + +failed_reiserfs_xattr_register_handlers: reiserfs_proc_unregister_global ("version"); reiserfs_proc_info_global_done (); destroy_inodecache (); @@ -1542,6 +2126,7 @@ init_reiserfs_fs ( void ) static void __exit exit_reiserfs_fs ( void ) { + reiserfs_xattr_unregister_handlers (); reiserfs_proc_unregister_global ("version"); reiserfs_proc_info_global_done (); unregister_filesystem (& reiserfs_fs_type);