Skip to content

Commit 9e33d69

Browse files
jankaraMark Fasheh
authored andcommitted
ocfs2: Implementation of local and global quota file handling
For each quota type each node has local quota file. In this file it stores changes users have made to disk usage via this node. Once in a while this information is synced to global file (and thus with other nodes) so that limits enforcement at least aproximately works. Global quota files contain all the information about usage and limits. It's mostly handled by the generic VFS code (which implements a trie of structures inside a quota file). We only have to provide functions to convert structures from on-disk format to in-memory one. We also have to provide wrappers for various quota functions starting transactions and acquiring necessary cluster locks before the actual IO is really started. Signed-off-by: Jan Kara <[email protected]> Signed-off-by: Mark Fasheh <[email protected]>
1 parent bbbd0eb commit 9e33d69

File tree

13 files changed

+2165
-5
lines changed

13 files changed

+2165
-5
lines changed

fs/ocfs2/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ ocfs2-objs := \
3535
sysfile.o \
3636
uptodate.o \
3737
ver.o \
38+
quota_local.o \
39+
quota_global.o \
3840
xattr.o
3941

4042
ifeq ($(CONFIG_OCFS2_FS_POSIX_ACL),y)

fs/ocfs2/cluster/masklog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
#define ML_QUORUM 0x0000000008000000ULL /* net connection quorum */
114114
#define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */
115115
#define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */
116+
#define ML_QUOTA 0x0000000040000000ULL /* ocfs2 quota operations */
116117
/* bits that are infrequently given and frequently matched in the high word */
117118
#define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */
118119
#define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */

fs/ocfs2/dlmglue.c

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <linux/debugfs.h>
3333
#include <linux/seq_file.h>
3434
#include <linux/time.h>
35+
#include <linux/quotaops.h>
3536

3637
#define MLOG_MASK_PREFIX ML_DLM_GLUE
3738
#include <cluster/masklog.h>
@@ -51,6 +52,7 @@
5152
#include "slot_map.h"
5253
#include "super.h"
5354
#include "uptodate.h"
55+
#include "quota.h"
5456

5557
#include "buffer_head_io.h"
5658

@@ -68,6 +70,7 @@ struct ocfs2_mask_waiter {
6870
static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres);
6971
static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres);
7072
static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres);
73+
static struct ocfs2_super *ocfs2_get_qinfo_osb(struct ocfs2_lock_res *lockres);
7174

7275
/*
7376
* Return value from ->downconvert_worker functions.
@@ -102,6 +105,7 @@ static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres,
102105
static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
103106
struct ocfs2_lock_res *lockres);
104107

108+
static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres);
105109

106110
#define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
107111

@@ -258,6 +262,12 @@ static struct ocfs2_lock_res_ops ocfs2_flock_lops = {
258262
.flags = 0,
259263
};
260264

265+
static struct ocfs2_lock_res_ops ocfs2_qinfo_lops = {
266+
.set_lvb = ocfs2_set_qinfo_lvb,
267+
.get_osb = ocfs2_get_qinfo_osb,
268+
.flags = LOCK_TYPE_REQUIRES_REFRESH | LOCK_TYPE_USES_LVB,
269+
};
270+
261271
static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
262272
{
263273
return lockres->l_type == OCFS2_LOCK_TYPE_META ||
@@ -279,6 +289,13 @@ static inline struct ocfs2_dentry_lock *ocfs2_lock_res_dl(struct ocfs2_lock_res
279289
return (struct ocfs2_dentry_lock *)lockres->l_priv;
280290
}
281291

292+
static inline struct ocfs2_mem_dqinfo *ocfs2_lock_res_qinfo(struct ocfs2_lock_res *lockres)
293+
{
294+
BUG_ON(lockres->l_type != OCFS2_LOCK_TYPE_QINFO);
295+
296+
return (struct ocfs2_mem_dqinfo *)lockres->l_priv;
297+
}
298+
282299
static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres)
283300
{
284301
if (lockres->l_ops->get_osb)
@@ -507,6 +524,13 @@ static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres)
507524
return OCFS2_SB(inode->i_sb);
508525
}
509526

527+
static struct ocfs2_super *ocfs2_get_qinfo_osb(struct ocfs2_lock_res *lockres)
528+
{
529+
struct ocfs2_mem_dqinfo *info = lockres->l_priv;
530+
531+
return OCFS2_SB(info->dqi_gi.dqi_sb);
532+
}
533+
510534
static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres)
511535
{
512536
struct ocfs2_file_private *fp = lockres->l_priv;
@@ -609,6 +633,17 @@ void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
609633
lockres->l_flags |= OCFS2_LOCK_NOCACHE;
610634
}
611635

636+
void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres,
637+
struct ocfs2_mem_dqinfo *info)
638+
{
639+
ocfs2_lock_res_init_once(lockres);
640+
ocfs2_build_lock_name(OCFS2_LOCK_TYPE_QINFO, info->dqi_gi.dqi_type,
641+
0, lockres->l_name);
642+
ocfs2_lock_res_init_common(OCFS2_SB(info->dqi_gi.dqi_sb), lockres,
643+
OCFS2_LOCK_TYPE_QINFO, &ocfs2_qinfo_lops,
644+
info);
645+
}
646+
612647
void ocfs2_lock_res_free(struct ocfs2_lock_res *res)
613648
{
614649
mlog_entry_void();
@@ -3445,6 +3480,117 @@ static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres,
34453480
return UNBLOCK_CONTINUE_POST;
34463481
}
34473482

3483+
static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres)
3484+
{
3485+
struct ocfs2_qinfo_lvb *lvb;
3486+
struct ocfs2_mem_dqinfo *oinfo = ocfs2_lock_res_qinfo(lockres);
3487+
struct mem_dqinfo *info = sb_dqinfo(oinfo->dqi_gi.dqi_sb,
3488+
oinfo->dqi_gi.dqi_type);
3489+
3490+
mlog_entry_void();
3491+
3492+
lvb = (struct ocfs2_qinfo_lvb *)ocfs2_dlm_lvb(&lockres->l_lksb);
3493+
lvb->lvb_version = OCFS2_QINFO_LVB_VERSION;
3494+
lvb->lvb_bgrace = cpu_to_be32(info->dqi_bgrace);
3495+
lvb->lvb_igrace = cpu_to_be32(info->dqi_igrace);
3496+
lvb->lvb_syncms = cpu_to_be32(oinfo->dqi_syncms);
3497+
lvb->lvb_blocks = cpu_to_be32(oinfo->dqi_gi.dqi_blocks);
3498+
lvb->lvb_free_blk = cpu_to_be32(oinfo->dqi_gi.dqi_free_blk);
3499+
lvb->lvb_free_entry = cpu_to_be32(oinfo->dqi_gi.dqi_free_entry);
3500+
3501+
mlog_exit_void();
3502+
}
3503+
3504+
void ocfs2_qinfo_unlock(struct ocfs2_mem_dqinfo *oinfo, int ex)
3505+
{
3506+
struct ocfs2_lock_res *lockres = &oinfo->dqi_gqlock;
3507+
struct ocfs2_super *osb = OCFS2_SB(oinfo->dqi_gi.dqi_sb);
3508+
int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
3509+
3510+
mlog_entry_void();
3511+
if (!ocfs2_is_hard_readonly(osb) && !ocfs2_mount_local(osb))
3512+
ocfs2_cluster_unlock(osb, lockres, level);
3513+
mlog_exit_void();
3514+
}
3515+
3516+
static int ocfs2_refresh_qinfo(struct ocfs2_mem_dqinfo *oinfo)
3517+
{
3518+
struct mem_dqinfo *info = sb_dqinfo(oinfo->dqi_gi.dqi_sb,
3519+
oinfo->dqi_gi.dqi_type);
3520+
struct ocfs2_lock_res *lockres = &oinfo->dqi_gqlock;
3521+
struct ocfs2_qinfo_lvb *lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
3522+
struct buffer_head *bh;
3523+
struct ocfs2_global_disk_dqinfo *gdinfo;
3524+
int status = 0;
3525+
3526+
if (lvb->lvb_version == OCFS2_QINFO_LVB_VERSION) {
3527+
info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace);
3528+
info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace);
3529+
oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms);
3530+
oinfo->dqi_gi.dqi_blocks = be32_to_cpu(lvb->lvb_blocks);
3531+
oinfo->dqi_gi.dqi_free_blk = be32_to_cpu(lvb->lvb_free_blk);
3532+
oinfo->dqi_gi.dqi_free_entry =
3533+
be32_to_cpu(lvb->lvb_free_entry);
3534+
} else {
3535+
bh = ocfs2_read_quota_block(oinfo->dqi_gqinode, 0, &status);
3536+
if (!bh) {
3537+
mlog_errno(status);
3538+
goto bail;
3539+
}
3540+
gdinfo = (struct ocfs2_global_disk_dqinfo *)
3541+
(bh->b_data + OCFS2_GLOBAL_INFO_OFF);
3542+
info->dqi_bgrace = le32_to_cpu(gdinfo->dqi_bgrace);
3543+
info->dqi_igrace = le32_to_cpu(gdinfo->dqi_igrace);
3544+
oinfo->dqi_syncms = le32_to_cpu(gdinfo->dqi_syncms);
3545+
oinfo->dqi_gi.dqi_blocks = le32_to_cpu(gdinfo->dqi_blocks);
3546+
oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(gdinfo->dqi_free_blk);
3547+
oinfo->dqi_gi.dqi_free_entry =
3548+
le32_to_cpu(gdinfo->dqi_free_entry);
3549+
brelse(bh);
3550+
ocfs2_track_lock_refresh(lockres);
3551+
}
3552+
3553+
bail:
3554+
return status;
3555+
}
3556+
3557+
/* Lock quota info, this function expects at least shared lock on the quota file
3558+
* so that we can safely refresh quota info from disk. */
3559+
int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex)
3560+
{
3561+
struct ocfs2_lock_res *lockres = &oinfo->dqi_gqlock;
3562+
struct ocfs2_super *osb = OCFS2_SB(oinfo->dqi_gi.dqi_sb);
3563+
int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
3564+
int status = 0;
3565+
3566+
mlog_entry_void();
3567+
3568+
/* On RO devices, locking really isn't needed... */
3569+
if (ocfs2_is_hard_readonly(osb)) {
3570+
if (ex)
3571+
status = -EROFS;
3572+
goto bail;
3573+
}
3574+
if (ocfs2_mount_local(osb))
3575+
goto bail;
3576+
3577+
status = ocfs2_cluster_lock(osb, lockres, level, 0, 0);
3578+
if (status < 0) {
3579+
mlog_errno(status);
3580+
goto bail;
3581+
}
3582+
if (!ocfs2_should_refresh_lock_res(lockres))
3583+
goto bail;
3584+
/* OK, we have the lock but we need to refresh the quota info */
3585+
status = ocfs2_refresh_qinfo(oinfo);
3586+
if (status)
3587+
ocfs2_qinfo_unlock(oinfo, ex);
3588+
ocfs2_complete_lock_res_refresh(lockres, status);
3589+
bail:
3590+
mlog_exit(status);
3591+
return status;
3592+
}
3593+
34483594
/*
34493595
* This is the filesystem locking protocol. It provides the lock handling
34503596
* hooks for the underlying DLM. It has a maximum version number.

fs/ocfs2/dlmglue.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ struct ocfs2_meta_lvb {
4949
__be32 lvb_reserved2;
5050
};
5151

52+
#define OCFS2_QINFO_LVB_VERSION 1
53+
54+
struct ocfs2_qinfo_lvb {
55+
__u8 lvb_version;
56+
__u8 lvb_reserved[3];
57+
__be32 lvb_bgrace;
58+
__be32 lvb_igrace;
59+
__be32 lvb_syncms;
60+
__be32 lvb_blocks;
61+
__be32 lvb_free_blk;
62+
__be32 lvb_free_entry;
63+
};
64+
5265
/* ocfs2_inode_lock_full() 'arg_flags' flags */
5366
/* don't wait on recovery. */
5467
#define OCFS2_META_LOCK_RECOVERY (0x01)
@@ -69,6 +82,9 @@ void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,
6982
struct ocfs2_file_private;
7083
void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
7184
struct ocfs2_file_private *fp);
85+
struct ocfs2_mem_dqinfo;
86+
void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres,
87+
struct ocfs2_mem_dqinfo *info);
7288
void ocfs2_lock_res_free(struct ocfs2_lock_res *res);
7389
int ocfs2_create_new_inode_locks(struct inode *inode);
7490
int ocfs2_drop_inode_locks(struct inode *inode);
@@ -103,6 +119,9 @@ int ocfs2_dentry_lock(struct dentry *dentry, int ex);
103119
void ocfs2_dentry_unlock(struct dentry *dentry, int ex);
104120
int ocfs2_file_lock(struct file *file, int ex, int trylock);
105121
void ocfs2_file_unlock(struct file *file);
122+
int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex);
123+
void ocfs2_qinfo_unlock(struct ocfs2_mem_dqinfo *oinfo, int ex);
124+
106125

107126
void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres);
108127
void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,

fs/ocfs2/file.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,9 @@ static int ocfs2_set_inode_size(handle_t *handle,
304304
return status;
305305
}
306306

307-
static int ocfs2_simple_size_update(struct inode *inode,
308-
struct buffer_head *di_bh,
309-
u64 new_i_size)
307+
int ocfs2_simple_size_update(struct inode *inode,
308+
struct buffer_head *di_bh,
309+
u64 new_i_size)
310310
{
311311
int ret;
312312
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);

fs/ocfs2/file.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ int ocfs2_add_inode_data(struct ocfs2_super *osb,
5151
struct ocfs2_alloc_context *data_ac,
5252
struct ocfs2_alloc_context *meta_ac,
5353
enum ocfs2_alloc_restarted *reason_ret);
54+
int ocfs2_simple_size_update(struct inode *inode,
55+
struct buffer_head *di_bh,
56+
u64 new_i_size);
5457
int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size,
5558
u64 zero_to);
5659
int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);

fs/ocfs2/inode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ int ocfs2_mark_inode_dirty(handle_t *handle,
142142
struct buffer_head *bh);
143143
int ocfs2_aio_read(struct file *file, struct kiocb *req, struct iocb *iocb);
144144
int ocfs2_aio_write(struct file *file, struct kiocb *req, struct iocb *iocb);
145+
struct buffer_head *ocfs2_bread(struct inode *inode,
146+
int block, int *err, int reada);
145147

146148
void ocfs2_set_inode_flags(struct inode *inode);
147149
void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi);

0 commit comments

Comments
 (0)