ocfs2: Implementation of local and global quota file handling
PATCH 1/1 ocfs2: Implementation of local and global quota file handling
--- fs/ocfs2/Makefile | 2 + fs/ocfs2/cluster/masklog.h | 1 + fs/ocfs2/dlmglue.c | 137 +++++++ fs/ocfs2/dlmglue.h | 17 + fs/ocfs2/file.c | 6 +- fs/ocfs2/file.h | 4 + fs/ocfs2/journal.h | 15 + fs/ocfs2/ocfs2_lockid.h | 5 + fs/ocfs2/quota.h | 182 ++++++++++ fs/ocfs2/quota_global.c | 836 +++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/quota_local.c | 842 ++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/super.c | 35 ++- 12 files changed, 2077 insertions(+), 5 deletions(-) create mode 100644 fs/ocfs2/quota.h create mode 100644 fs/ocfs2/quota_global.c create mode 100644 fs/ocfs2/quota_local.c
fs/ocfs2/Makefile +2 -0
@@ -34,6 +34,8 @@ ocfs2-objs := \ symlink.o \ sysfile.o \ uptodate.o \ + quota_local.o \ + quota_global.o \ ver.o ocfs2_stackglue-objs := stackglue.o
fs/ocfs2/cluster/masklog.h +1 -0
@@ -112,6 +112,7 @@#define ML_CONN 0x0000000004000000ULL/* net connection management */ #define ML_QUORUM 0x0000000008000000ULL/* net connection quorum */ #define ML_EXPORT 0x0000000010000000ULL/* ocfs2 export operations */ +#define ML_QUOTA 0x0000000020000000ULL/* ocfs2 quota operations */ /* bits that are infrequently given and frequently matched in the high word */ #define ML_ERROR 0x0000000100000000ULL/* sent to KERN_ERR */ #define ML_NOTICE 0x0000000200000000ULL/* setn to KERN_NOTICE */
fs/ocfs2/dlmglue.c +137 -0
191 lines not on this page · raw message
fs/ocfs2/dlmglue.h +17 -0
@@ -49,6 +49,17 @@ struct ocfs2_meta_lvb {__be32 lvb_reserved2; }; +struct ocfs2_qinfo_lvb { +__u8 lvb_version; +__u8 lvb_reserved[3 ]; +__be32 lvb_bgrace; +__be32 lvb_igrace; +__be32 lvb_syncms; +__be32 lvb_blocks; +__be32 lvb_free_blk; +__be32 lvb_free_entry; +}; +/* ocfs2_inode_lock_full() 'arg_flags' flags */ /* don't wait on recovery. */ #define OCFS2_META_LOCK_RECOVERY (0x01)
@@ -69,6 +80,9 @@ void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,struct ocfs2_file_private ;void ocfs2_file_lock_res_init (struct ocfs2_lock_res *lockres,struct ocfs2_file_private *fp); +struct ocfs2_mem_dqinfo ; +void ocfs2_qinfo_lock_res_init (struct ocfs2_lock_res *lockres, +struct ocfs2_mem_dqinfo *info);void ocfs2_lock_res_free (struct ocfs2_lock_res *res);int ocfs2_create_new_inode_locks (struct inode *inode);int ocfs2_drop_inode_locks (struct inode *inode);
@@ -103,6 +117,9 @@ int ocfs2_dentry_lock(struct dentry *dentry, int ex);void ocfs2_dentry_unlock (struct dentry *dentry,int ex);int ocfs2_file_lock (struct file *file,int ex,int trylock);void ocfs2_file_unlock (struct file *file); +int ocfs2_qinfo_lock (struct ocfs2_mem_dqinfo *oinfo,int ex); +void ocfs2_qinfo_unlock (struct ocfs2_mem_dqinfo *oinfo,int ex); +void ocfs2_mark_lockres_freeing (struct ocfs2_lock_res *lockres); void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
fs/ocfs2/file.c +3 -3
@@ -302,9 +302,9 @@ bail:return status; } -static int ocfs2_simple_size_update (struct inode *inode, -struct buffer_head *di_bh, -u64 new_i_size) +int ocfs2_simple_size_update (struct inode *inode, +struct buffer_head *di_bh, +u64 new_i_size) {int ret;struct ocfs2_super *osb =OCFS2_SB (inode->i_sb);
fs/ocfs2/file.h +4 -0
@@ -53,6 +53,10 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret); + +int ocfs2_simple_size_update (struct inode *inode, +struct buffer_head *di_bh, +u64 new_i_size);int ocfs2_extend_no_holes (struct inode *inode,u64 new_i_size,u64 zero_to); int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
fs/ocfs2/journal.h +15 -0
@@ -340,6 +340,21 @@ int ocfs2_journal_dirty_data(handle_t *handle,#define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3 \ + OCFS2_UNLINK_CREDITS) +/* global quotafile inode update, data block */ +#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) + +/* +* The two writes below can accidentally see global info dirty due +* to set_info() quotactl so make them prepared for the writes. +*/ +/* quota data block, global info */ +/* Write to local quota file */ +#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + 1) + +/* global quota data block, local quota data block, global quota inode, +* global quota info */ +#define OCFS2_QSYNC_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 3) +static inline int ocfs2_calc_extend_credits (struct super_block *sb,struct ocfs2_dinode *fe,u32 bits_wanted)
fs/ocfs2/ocfs2_lockid.h +5 -0
@@ -46,6 +46,7 @@ enum ocfs2_lock_type {OCFS2_LOCK_TYPE_DENTRY ,OCFS2_LOCK_TYPE_OPEN ,OCFS2_LOCK_TYPE_FLOCK , +OCFS2_LOCK_TYPE_QINFO , OCFS2_NUM_LOCK_TYPES };
@@ -77,6 +78,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)case OCFS2_LOCK_TYPE_FLOCK : c ='F' ;break ; +case OCFS2_LOCK_TYPE_QINFO : + c ='Q' ; +break ;default : c ='\0' ; }
@@ -95,6 +99,7 @@ static char *ocfs2_lock_type_strings[] = { [OCFS2_LOCK_TYPE_DENTRY] = "Dentry", [OCFS2_LOCK_TYPE_OPEN] = "Open", [OCFS2_LOCK_TYPE_FLOCK] = "Flock", + [OCFS2_LOCK_TYPE_QINFO] = "Quota", };static inline const char *ocfs2_lock_type_string (enum ocfs2_lock_type type)
fs/ocfs2/quota.h new file +182 -0
182 lines not on this page · raw message
fs/ocfs2/quota_global.c new file +836 -0
836 lines not on this page · raw message
fs/ocfs2/quota_local.c new file +842 -0
842 lines not on this page · raw message
fs/ocfs2/super.c +33 -2
@@ -64,10 +64,13 @@#include "sysfile.h" #include "uptodate.h" #include "ver.h" +#include "quota.h" #include "buffer_head_io.h" static struct kmem_cache *ocfs2_inode_cachep =NULL ; +struct kmem_cache *ocfs2_dquot_cachep; +struct kmem_cache *ocfs2_qf_chunk_cachep;/* OCFS2 needs to schedule several differnt types of work which * require cluster locking, disk I/O, recovery waits, etc. Since these
@@ -136,6 +139,8 @@ static const struct super_operations ocfs2_sops = { .put_super = ocfs2_put_super, .remount_fs = ocfs2_remount, .show_options = ocfs2_show_options, + .quota_read = ocfs2_quota_read, + .quota_write = ocfs2_quota_write, };enum {
@@ -1171,8 +1176,27 @@ static int ocfs2_initialize_mem_caches(void) (SLAB_HWCACHE_ALIGN |SLAB_RECLAIM_ACCOUNT |SLAB_MEM_SPREAD ), ocfs2_inode_init_once); -if (!ocfs2_inode_cachep) + ocfs2_dquot_cachep =kmem_cache_create ("ocfs2_dquot_cache" , +sizeof (struct ocfs2_dquot ), +0 , + (SLAB_HWCACHE_ALIGN |SLAB_RECLAIM_ACCOUNT | +SLAB_MEM_SPREAD ), +NULL ); + ocfs2_qf_chunk_cachep =kmem_cache_create ("ocfs2_qf_chunk_cache" , +sizeof (struct ocfs2_quota_chunk ), +0 , + (SLAB_RECLAIM_ACCOUNT |SLAB_MEM_SPREAD ), +NULL ); +if (!ocfs2_inode_cachep || !ocfs2_dquot_cachep || + !ocfs2_qf_chunk_cachep) { +if (ocfs2_inode_cachep) +kmem_cache_destroy (ocfs2_inode_cachep); +if (ocfs2_dquot_cachep) +kmem_cache_destroy (ocfs2_dquot_cachep); +if (ocfs2_qf_chunk_cachep) +kmem_cache_destroy (ocfs2_qf_chunk_cachep);return -ENOMEM ; + }return 0 ; }
@@ -1181,8 +1205,15 @@ static void ocfs2_free_mem_caches(void) {if (ocfs2_inode_cachep)kmem_cache_destroy (ocfs2_inode_cachep); - ocfs2_inode_cachep =NULL ; + +if (ocfs2_dquot_cachep) +kmem_cache_destroy (ocfs2_dquot_cachep); + ocfs2_dquot_cachep =NULL ; + +if (ocfs2_qf_chunk_cachep) +kmem_cache_destroy (ocfs2_qf_chunk_cachep); + ocfs2_qf_chunk_cachep =NULL ; } static int ocfs2_get_sector(struct super_block *sb,
Signature · 1 line
1.5.2.4
PATCH 1/1 ocfs2: Implementation of local and global quota file handling
Quoted 1 line · Jan Kara
Signed-off-by Jan Kara <[email protected]>
The commit message could maybe use a little discussion of what
quota bits go in the local file and what goes in the global. It seems like less is written to the global file, but I might be wrong about that (eg, generic quota code might be writing there).
fs/ocfs2/quota.h line 5
Quoted 11 lines
fs/ocfs2/quota.h new file +5
-0@@ -0,0 +1,182 @@ +/* +* quota.h for OCFS2 +* +* On disk quota structures for local and global quota file, in-memory +* structures.
I'm thinking the on-disk structures belong in ocfs2_fs.h, which
is where we define the disk format, and the in-memory structures belong here.
fs/ocfs2/quota.h line 110
Quoted 8 lines
fs/ocfs2/quota.h new file +8
-0+/* Information header of local quota file (immediately follows the generic +* header) */ +struct ocfs2_local_disk_dqinfo { +__le32 dqi_flags;/* Flags for quota file */ +__le32 dqi_chunks;/* Number of chunks of quota structures +* with a bitmap */ +__le32 dqi_blocks;/* Number of blocks allocated for quota file */ +};
Also, we'd love the on-disk structures to have the size/offset
annotations we put in ocfs2_fs.h. Yes, some of the smaller structures are pretty obvious, but having the hexadecimal values in the header often helps reading binary dumps.
fs/ocfs2/quota.h line 20
Quoted 7 lines
fs/ocfs2/quota.h new file +7
-0+while (toread >0 ) { + tocopy =min (sb->s_blocksize - offset, toread); + bh =ocfs2_bread (gqinode, blk, &err,0 ); +if (!bh) { +mlog_errno (err); +return err; + }
Fair warning - you use ocfs2_bread() a lot in here, butocfs2_bread() is going away. Before I realized you were going to use it (and conceptually that makes sense), it moved into fs/ocfs2/dir.c. Then it morphed into ocfs2_read_dir_block()as part of my read-metadata branch at
http://oss.oracle.com/git/jlbec/linux-2.6.git/?p=jlbec/linux-2.6.git;a=shortlog;h=read-metadata
In the end, this code will be doing ocfs2_read_quota_block(), or
perhaps different variations thereof (if there are different types of blocks in the quota file). I'm going to refactor ocfs2_read_dir_block() and introduce the function ocfs2_read_virt_blocks(). It will look exactly like ocfs2_read_blocks() does in my read-metadata branch, except that it will take virtual block numbers rather than physical ones. Thus, you'll be able to write ocfs2_read_quota_block() as a thin wrapper around it, and replace your ocfs2_bread() calls easily.
Obviously, you don't have to worry too much until this code
moves atop the latest kernel code. And I'm happy to help.
Quoted 20 lines
fs/ocfs2/quota.h new file +20
-0+/* Write bufferhead into the fs */ +static int ocfs2_modify_bh (struct inode *inode,struct buffer_head *bh, +void (*modify)(struct buffer_head *,void *),void *private) +{ +struct super_block *sb = inode->i_sb; +handle_t *handle; +int status; + + handle =ocfs2_start_trans (OCFS2_SB (sb),1 ); +if (IS_ERR (handle)) { + status =PTR_ERR (handle); +mlog_errno (status); +return status; + } + status =ocfs2_journal_access (handle, inode, bh, +OCFS2_JOURNAL_ACCESS_WRITE ); +if (status <0 ) { +mlog_errno (status); +ocfs2_commit_trans (OCFS2_SB (sb), handle); +return status;
fs/ocfs2/quota.h line 50
Quoted 10 lines
fs/ocfs2/quota.h new file +10
-0+ } +lock_buffer (bh); +modify (bh, private); +unlock_buffer (bh); + status =ocfs2_journal_dirty (handle, bh); +if (status <0 ) { +mlog_errno (status); +ocfs2_commit_trans (OCFS2_SB (sb), handle); +return status; + }
ocfs2_journal_dirty() can't sanely return an error, becausejournal_dirty() can't either. Someday it will become void. You can take out all the error checking of your ocfs2_journal_dirty() calls.
Is this modify_bh() function the reason you need nested
transactions? The callers can't be audited for their transaction state?
Joel
Signature · 10 lines
"It is not the function of our government to keep the citizen from falling into error; it is the function of the citizen to keep the government from falling into error." - Robert H. Jackson Joel Becker Principal Software Developer Oracle E-mail: joel.becker at oracle.com Phone: (650) 506-8127
PATCH 1/1 ocfs2: Implementation of local and global quota file handling
Quoted 7 lines · Joel Becker
Quoted 1 line · Jan Kara
Signed-off-by Jan Kara <[email protected]>The commit message could maybe use a little discussion of what
quota bits go in the local file and what goes in the global. It seems like less is written to the global file, but I might be wrong about that (eg, generic quota code might be writing there).
Well, global file is actually more complicated, but generic code handles
that. In terms of frequency, we write more often to the local file, that is right. It is a good idea to add there a description what goes where to the changelog. I'll do that.
Quoted 7 lines
Quoted 7 lines
fs/ocfs2/quota.h new file +1
-0@@ -0,0 +1,182 @@ +/*
Quoted 8 lines
fs/ocfs2/quota.h line 5
Quoted 4 lines
fs/ocfs2/quota.h new file +4
-0+* quota.h for OCFS2 +* +* On disk quota structures for local and global quota file, in-memory +* structures. I'm thinking the on-disk structures belong in
ocfs2_fs.h, which
is where we define the disk format, and the in-memory structures belong here.
OK, will do.
Quoted 5 lines
Quoted 5 lines
fs/ocfs2/quota.h new file +5
-0+/* Information header of local quota file (immediately follows the generic +* header) */ +struct ocfs2_local_disk_dqinfo { +__le32 dqi_flags;/* Flags for quota file */ +__le32 dqi_chunks;/* Number of chunks of quota structures
Quoted 8 lines
fs/ocfs2/quota.h line 110
Quoted 3 lines
fs/ocfs2/quota.h new file +3
-0+* with a bitmap */ +__le32 dqi_blocks;/* Number of blocks allocated for quota file */ +};Also, we'd love the on-disk structures to have the size/offset
annotations we put inocfs2_fs.h. Yes, some of the smaller structures are pretty obvious, but having the hexadecimal values in the header often helps reading binary dumps.
Will do.
Quoted 16 lines
fs/ocfs2/quota.h line 20
Quoted 7 lines
fs/ocfs2/quota.h new file +7
-0+while (toread >0 ) { + tocopy =min (sb->s_blocksize - offset, toread); + bh =ocfs2_bread (gqinode, blk, &err,0 ); +if (!bh) { +mlog_errno (err); +return err; + }Fair warning - you use
ocfs2_bread()a lot in here, butocfs2_bread()is going away. Before I realized you were going to use it (and conceptually that makes sense), it moved intofs/ocfs2/dir.c. Then it morphed into ocfs2_read_dir_block()as part of my read-metadata branch at
http://oss.oracle.com/git/jlbec/linux-2.6.git/?p=jlbec/linux-2.6.git;a=shortlog;h=read-metadata
In the end, this code will be doingocfs2_read_quota_block(), or
perhaps different variations thereof (if there are different types of
Quoted 8 lines
blocks in the quota file). I'm going to refactor
ocfs2_read_dir_block()and introduce the functionocfs2_read_virt_blocks(). It will look exactly likeocfs2_read_blocks()does in my read-metadata branch, except that it will take virtual block numbers rather than physical ones. Thus, you'll be able to writeocfs2_read_quota_block()as a thin wrapper around it, and replace yourocfs2_bread()calls easily.
Obviously, you don't have to worry too much until this code
moves atop the latest kernel code. And I'm happy to help.
I am warned ;) Seriously, when this happens it's trivial to fix and for
SLES11 I need a working version on top of 2.6.27... So I'll change this later when integrating the patches upstream.
Quoted 26 lines
Quoted 26 lines
fs/ocfs2/quota.h new file +26
-0+/* Write bufferhead into the fs */ +static int ocfs2_modify_bh (struct inode *inode,struct buffer_head *bh, +void (*modify)(struct buffer_head *,void *),void *private) +{ +struct super_block *sb = inode->i_sb; +handle_t *handle; +int status; + + handle =ocfs2_start_trans (OCFS2_SB (sb),1 ); +if (IS_ERR (handle)) { + status =PTR_ERR (handle); +mlog_errno (status); +return status; + } + status =ocfs2_journal_access (handle, inode, bh, +OCFS2_JOURNAL_ACCESS_WRITE ); +if (status <0 ) { +mlog_errno (status); +ocfs2_commit_trans (OCFS2_SB (sb), handle); +return status; + } +lock_buffer (bh); +modify (bh, private); +unlock_buffer (bh); + status =ocfs2_journal_dirty (handle, bh); +if (status <0 ) {
Quoted 8 lines
fs/ocfs2/quota.h line 50
Quoted 4 lines
fs/ocfs2/quota.h new file +4
-0+mlog_errno (status); +ocfs2_commit_trans (OCFS2_SB (sb), handle); +return status; + }
ocfs2_journal_dirty()can't sanely return an error, becausejournal_dirty()can't either. Someday it will become void. You can take out all the error checking of yourocfs2_journal_dirty()calls.
Thanks for letting me know. I'm not sure if I'll change that for the
first version but I'll put that on my todo list.
Quoted 2 lines
Is this
modify_bh()function the reason you need nested
transactions? The callers can't be audited for their transaction state?
No, modify_bh() is just a helper for updating quota file block headers,
I don't think it's ever called when the trasaction is already started. There are more subtle reasons why I wanted nested transactions as I described in one of my previous emails...
Thanks for the review.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR