cregit-Linux how code gets into the kernel

Release 4.10 fs/ocfs2/quota_local.c

Directory: fs/ocfs2
/*
 *  Implementation of operations over local quota file
 */

#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/quota.h>
#include <linux/quotaops.h>
#include <linux/module.h>

#include <cluster/masklog.h>

#include "ocfs2_fs.h"
#include "ocfs2.h"
#include "inode.h"
#include "alloc.h"
#include "file.h"
#include "buffer_head_io.h"
#include "journal.h"
#include "sysfile.h"
#include "dlmglue.h"
#include "quota.h"
#include "uptodate.h"
#include "super.h"
#include "ocfs2_trace.h"

/* Number of local quota structures per block */

static inline unsigned int ol_quota_entries_per_block(struct super_block *sb) { return ((sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE) / sizeof(struct ocfs2_local_disk_dqblk)); }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara30100.00%1100.00%
Total30100.00%1100.00%

/* Number of blocks with entries in one chunk */
static inline unsigned int ol_chunk_blocks(struct super_block *sb) { return ((sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) - OCFS2_QBLK_RESERVED_SPACE) << 3) / ol_quota_entries_per_block(sb); }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara37100.00%1100.00%
Total37100.00%1100.00%

/* Number of entries in a chunk bitmap */
static unsigned int ol_chunk_entries(struct super_block *sb) { return ol_chunk_blocks(sb) * ol_quota_entries_per_block(sb); }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara23100.00%1100.00%
Total23100.00%1100.00%

/* Offset of the chunk in quota file */
static unsigned int ol_quota_chunk_block(struct super_block *sb, int c) { /* 1 block for local quota file info, 1 block per chunk for chunk info */ return 1 + (ol_chunk_blocks(sb) + 1) * c; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara30100.00%1100.00%
Total30100.00%1100.00%


static unsigned int ol_dqblk_block(struct super_block *sb, int c, int off) { int epb = ol_quota_entries_per_block(sb); return ol_quota_chunk_block(sb, c) + 1 + off / epb; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara40100.00%2100.00%
Total40100.00%2100.00%


static unsigned int ol_dqblk_block_off(struct super_block *sb, int c, int off) { int epb = ol_quota_entries_per_block(sb); return (off % epb) * sizeof(struct ocfs2_local_disk_dqblk); }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara39100.00%2100.00%
Total39100.00%2100.00%

/* Offset of the dquot structure in the quota file */
static loff_t ol_dqblk_off(struct super_block *sb, int c, int off) { return (ol_dqblk_block(sb, c, off) << sb->s_blocksize_bits) + ol_dqblk_block_off(sb, c, off); }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara42100.00%1100.00%
Total42100.00%1100.00%


static inline unsigned int ol_dqblk_block_offset(struct super_block *sb, loff_t off) { return off & ((1 << sb->s_blocksize_bits) - 1); }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara31100.00%1100.00%
Total31100.00%1100.00%

/* Compute offset in the chunk of a structure with the given offset */
static int ol_dqblk_chunk_off(struct super_block *sb, int c, loff_t off) { int epb = ol_quota_entries_per_block(sb); return ((off >> sb->s_blocksize_bits) - ol_quota_chunk_block(sb, c) - 1) * epb + ((unsigned int)(off & ((1 << sb->s_blocksize_bits) - 1))) / sizeof(struct ocfs2_local_disk_dqblk); }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara75100.00%1100.00%
Total75100.00%1100.00%

/* 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), OCFS2_QUOTA_BLOCK_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); return status; } status = ocfs2_journal_access_dq(handle, INODE_CACHE(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); ocfs2_journal_dirty(handle, bh); status = ocfs2_commit_trans(OCFS2_SB(sb), handle); if (status < 0) { mlog_errno(status); return status; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara17997.81%250.00%
joel beckerjoel becker42.19%250.00%
Total183100.00%4100.00%

/* * Read quota block from a given logical offset. * * This function acquires ip_alloc_sem and thus it must not be called with a * transaction started. */
static int ocfs2_read_quota_block(struct inode *inode, u64 v_block, struct buffer_head **bh) { int rc = 0; struct buffer_head *tmp = *bh; if (i_size_read(inode) >> inode->i_sb->s_blocksize_bits <= v_block) { ocfs2_error(inode->i_sb, "Quota file %llu is probably corrupted! Requested to read block %Lu but file has size only %Lu\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)v_block, (unsigned long long)i_size_read(inode)); return -EIO; } rc = ocfs2_read_virt_blocks(inode, v_block, 1, &tmp, 0, ocfs2_validate_quota_block); if (rc) mlog_errno(rc); /* If ocfs2_read_virt_blocks() got us a new bh, pass it up. */ if (!rc && !*bh) *bh = tmp; return rc; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara13699.27%150.00%
joe perchesjoe perches10.73%150.00%
Total137100.00%2100.00%

/* Check whether we understand format of quota files */
static int ocfs2_local_check_quota_file(struct super_block *sb, int type) { unsigned int lmagics[OCFS2_MAXQUOTAS] = OCFS2_LOCAL_QMAGICS; unsigned int lversions[OCFS2_MAXQUOTAS] = OCFS2_LOCAL_QVERSIONS; unsigned int gmagics[OCFS2_MAXQUOTAS] = OCFS2_GLOBAL_QMAGICS; unsigned int gversions[OCFS2_MAXQUOTAS] = OCFS2_GLOBAL_QVERSIONS; unsigned int ino[OCFS2_MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE, GROUP_QUOTA_SYSTEM_INODE }; struct buffer_head *bh = NULL; struct inode *linode = sb_dqopt(sb)->files[type]; struct inode *ginode = NULL; struct ocfs2_disk_dqheader *dqhead; int status, ret = 0; /* First check whether we understand local quota file */ status = ocfs2_read_quota_block(linode, 0, &bh); if (status) { mlog_errno(status); mlog(ML_ERROR, "failed to read quota file header (type=%d)\n", type); goto out_err; } dqhead = (struct ocfs2_disk_dqheader *)(bh->b_data); if (le32_to_cpu(dqhead->dqh_magic) != lmagics[type]) { mlog(ML_ERROR, "quota file magic does not match (%u != %u)," " type=%d\n", le32_to_cpu(dqhead->dqh_magic), lmagics[type], type); goto out_err; } if (le32_to_cpu(dqhead->dqh_version) != lversions[type]) { mlog(ML_ERROR, "quota file version does not match (%u != %u)," " type=%d\n", le32_to_cpu(dqhead->dqh_version), lversions[type], type); goto out_err; } brelse(bh); bh = NULL; /* Next check whether we understand global quota file */ ginode = ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type], OCFS2_INVALID_SLOT); if (!ginode) { mlog(ML_ERROR, "cannot get global quota file inode " "(type=%d)\n", type); goto out_err; } /* Since the header is read only, we don't care about locking */ status = ocfs2_read_quota_block(ginode, 0, &bh); if (status) { mlog_errno(status); mlog(ML_ERROR, "failed to read global quota file header " "(type=%d)\n", type); goto out_err; } dqhead = (struct ocfs2_disk_dqheader *)(bh->b_data); if (le32_to_cpu(dqhead->dqh_magic) != gmagics[type]) { mlog(ML_ERROR, "global quota file magic does not match " "(%u != %u), type=%d\n", le32_to_cpu(dqhead->dqh_magic), gmagics[type], type); goto out_err; } if (le32_to_cpu(dqhead->dqh_version) != gversions[type]) { mlog(ML_ERROR, "global quota file version does not match " "(%u != %u), type=%d\n", le32_to_cpu(dqhead->dqh_version), gversions[type], type); goto out_err; } ret = 1; out_err: brelse(bh); iput(ginode); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara42598.15%266.67%
joel beckerjoel becker81.85%133.33%
Total433100.00%3100.00%

/* Release given list of quota file chunks */
static void ocfs2_release_local_quota_bitmaps(struct list_head *head) { struct ocfs2_quota_chunk *pos, *next; list_for_each_entry_safe(pos, next, head, qc_chunk) { list_del(&pos->qc_chunk); brelse(pos->qc_headerbh); kmem_cache_free(ocfs2_qf_chunk_cachep, pos); } }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara53100.00%1100.00%
Total53100.00%1100.00%

/* Load quota bitmaps into memory */
static int ocfs2_load_local_quota_bitmaps(struct inode *inode, struct ocfs2_local_disk_dqinfo *ldinfo, struct list_head *head) { struct ocfs2_quota_chunk *newchunk; int i, status; INIT_LIST_HEAD(head); for (i = 0; i < le32_to_cpu(ldinfo->dqi_chunks); i++) { newchunk = kmem_cache_alloc(ocfs2_qf_chunk_cachep, GFP_NOFS); if (!newchunk) { ocfs2_release_local_quota_bitmaps(head); return -ENOMEM; } newchunk->qc_num = i; newchunk->qc_headerbh = NULL; status = ocfs2_read_quota_block(inode, ol_quota_chunk_block(inode->i_sb, i), &newchunk->qc_headerbh); if (status) { mlog_errno(status); kmem_cache_free(ocfs2_qf_chunk_cachep, newchunk); ocfs2_release_local_quota_bitmaps(head); return status; } list_add_tail(&newchunk->qc_chunk, head); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara14594.77%150.00%
joel beckerjoel becker85.23%150.00%
Total153100.00%2100.00%


static void olq_update_info(struct buffer_head *bh, void *private) { struct mem_dqinfo *info = private; struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv; struct ocfs2_local_disk_dqinfo *ldinfo; ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data + OCFS2_LOCAL_INFO_OFF); spin_lock(&dq_data_lock); ldinfo->dqi_flags = cpu_to_le32(oinfo->dqi_flags); ldinfo->dqi_chunks = cpu_to_le32(oinfo->dqi_chunks); ldinfo->dqi_blocks = cpu_to_le32(oinfo->dqi_blocks); spin_unlock(&dq_data_lock); }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara96100.00%2100.00%
Total96100.00%2100.00%


static int ocfs2_add_recovery_chunk(struct super_block *sb, struct ocfs2_local_disk_chunk *dchunk, int chunk, struct list_head *head) { struct ocfs2_recovery_chunk *rc; rc = kmalloc(sizeof(struct ocfs2_recovery_chunk), GFP_NOFS); if (!rc) return -ENOMEM; rc->rc_chunk = chunk; rc->rc_bitmap = kmalloc(sb->s_blocksize, GFP_NOFS); if (!rc->rc_bitmap) { kfree(rc); return -ENOMEM; } memcpy(rc->rc_bitmap, dchunk->dqc_bitmap, (ol_chunk_entries(sb) + 7) >> 3); list_add_tail(&rc->rc_list, head); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara123100.00%2100.00%
Total123100.00%2100.00%


static void free_recovery_list(struct list_head *head) { struct ocfs2_recovery_chunk *next; struct ocfs2_recovery_chunk *rchunk; list_for_each_entry_safe(rchunk, next, head, rc_list) { list_del(&rchunk->rc_list); kfree(rchunk->rc_bitmap); kfree(rchunk); } }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara53100.00%1100.00%
Total53100.00%1100.00%


void ocfs2_free_quota_recovery(struct ocfs2_quota_recovery *rec) { int type; for (type = 0; type < OCFS2_MAXQUOTAS; type++) free_recovery_list(&(rec->r_list[type])); kfree(rec); }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara44100.00%2100.00%
Total44100.00%2100.00%

/* Load entries in our quota file we have to recover*/
static int ocfs2_recovery_load_quota(struct inode *lqinode, struct ocfs2_local_disk_dqinfo *ldinfo, int type, struct list_head *head) { struct super_block *sb = lqinode->i_sb; struct buffer_head *hbh; struct ocfs2_local_disk_chunk *dchunk; int i, chunks = le32_to_cpu(ldinfo->dqi_chunks); int status = 0; for (i = 0; i < chunks; i++) { hbh = NULL; status = ocfs2_read_quota_block(lqinode, ol_quota_chunk_block(sb, i), &hbh); if (status) { mlog_errno(status); break; } dchunk = (struct ocfs2_local_disk_chunk *)hbh->b_data; if (le32_to_cpu(dchunk->dqc_free) < ol_chunk_entries(sb)) status = ocfs2_add_recovery_chunk(sb, dchunk, i, head); brelse(hbh); if (status < 0) break; } if (status < 0) free_recovery_list(head); return status; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara16696.51%150.00%
joel beckerjoel becker63.49%150.00%
Total172100.00%2100.00%


static struct ocfs2_quota_recovery *ocfs2_alloc_quota_recovery(void) { int type; struct ocfs2_quota_recovery *rec; rec = kmalloc(sizeof(struct ocfs2_quota_recovery), GFP_NOFS); if (!rec) return NULL; for (type = 0; type < OCFS2_MAXQUOTAS; type++) INIT_LIST_HEAD(&(rec->r_list[type])); return rec; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara68100.00%2100.00%
Total68100.00%2100.00%

/* Load information we need for quota recovery into memory */
struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery( struct ocfs2_super *osb, int slot_num) { unsigned int feature[OCFS2_MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; unsigned int ino[OCFS2_MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, LOCAL_GROUP_QUOTA_SYSTEM_INODE }; struct super_block *sb = osb->sb; struct ocfs2_local_disk_dqinfo *ldinfo; struct inode *lqinode; struct buffer_head *bh; int type; int status = 0; struct ocfs2_quota_recovery *rec; printk(KERN_NOTICE "ocfs2: Beginning quota recovery on device (%s) for " "slot %u\n", osb->dev_str, slot_num); rec = ocfs2_alloc_quota_recovery(); if (!rec) return ERR_PTR(-ENOMEM); /* First init... */ for (type = 0; type < OCFS2_MAXQUOTAS; type++) { if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type])) continue; /* At this point, journal of the slot is already replayed so * we can trust metadata and data of the quota file */ lqinode = ocfs2_get_system_file_inode(osb, ino[type], slot_num); if (!lqinode) { status = -ENOENT; goto out; } status = ocfs2_inode_lock_full(lqinode, NULL, 1, OCFS2_META_LOCK_RECOVERY); if (status < 0) { mlog_errno(status); goto out_put; } /* Now read local header */ bh = NULL; status = ocfs2_read_quota_block(lqinode, 0, &bh); if (status) { mlog_errno(status); mlog(ML_ERROR, "failed to read quota file info header " "(slot=%d type=%d)\n", slot_num, type); goto out_lock; } ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data + OCFS2_LOCAL_INFO_OFF); status = ocfs2_recovery_load_quota(lqinode, ldinfo, type, &rec->r_list[type]); brelse(bh); out_lock: ocfs2_inode_unlock(lqinode, 1); out_put: iput(lqinode); if (status < 0) break; } out: if (status < 0) { ocfs2_free_quota_recovery(rec); rec = ERR_PTR(status); } return rec; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara31496.02%250.00%
sunil mushransunil mushran72.14%125.00%
joel beckerjoel becker61.83%125.00%
Total327100.00%4100.00%

/* Sync changes in local quota file into global quota file and * reinitialize local quota file. * The function expects local quota file to be already locked and * s_umount locked in shared mode. */
static int ocfs2_recover_local_quota_file(struct inode *lqinode, int type, struct ocfs2_quota_recovery *rec) { struct super_block *sb = lqinode->i_sb; struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; struct ocfs2_local_disk_chunk *dchunk; struct ocfs2_local_disk_dqblk *dqblk; struct dquot *dquot; handle_t *handle; struct buffer_head *hbh = NULL, *qbh = NULL; int status = 0; int bit, chunk; struct ocfs2_recovery_chunk *rchunk, *next; qsize_t spacechange, inodechange; trace_ocfs2_recover_local_quota_file((unsigned long)lqinode->i_ino, type); list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) { chunk = rchunk->rc_chunk; hbh = NULL; status = ocfs2_read_quota_block(lqinode, ol_quota_chunk_block(sb, chunk), &hbh); if (status) { mlog_errno(status); break; } dchunk = (struct ocfs2_local_disk_chunk *)hbh->b_data; for_each_set_bit(bit, rchunk->rc_bitmap, ol_chunk_entries(sb)) { qbh = NULL; status = ocfs2_read_quota_block(lqinode, ol_dqblk_block(sb, chunk, bit), &qbh); if (status) { mlog_errno(status); break; } dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data + ol_dqblk_block_off(sb, chunk, bit)); dquot = dqget(sb, make_kqid(&init_user_ns, type, le64_to_cpu(dqblk->dqb_id))); if (IS_ERR(dquot)) { status = PTR_ERR(dquot); mlog(ML_ERROR, "Failed to get quota structure " "for id %u, type %d. Cannot finish quota " "file recovery.\n", (unsigned)le64_to_cpu(dqblk->dqb_id), type); goto out_put_bh; } status = ocfs2_lock_global_qf(oinfo, 1); if (status < 0) { mlog_errno(status); goto out_put_dquot; } handle = ocfs2_start_trans(OCFS2_SB(sb), OCFS2_QSYNC_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); goto out_drop_lock; } mutex_lock(&sb_dqopt(sb)->dqio_mutex); spin_lock(&dq_data_lock); /* Add usage from quota entry into quota changes * of our node. Auxiliary variables are important * due to signedness */ spacechange = le64_to_cpu(dqblk->dqb_spacemod); inodechange = le64_to_cpu(dqblk->dqb_inodemod); dquot->dq_dqb.dqb_curspace += spacechange; dquot->dq_dqb.dqb_curinodes += inodechange; spin_unlock(&dq_data_lock); /* We want to drop reference held by the crashed * node. Since we have our own reference we know * global structure actually won't be freed. */ status = ocfs2_global_release_dquot(dquot); if (status < 0) { mlog_errno(status); goto out_commit; } /* Release local quota file entry */ status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode), qbh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto out_commit; } lock_buffer(qbh); WARN_ON(!ocfs2_test_bit_unaligned(bit, dchunk->dqc_bitmap)); ocfs2_clear_bit_unaligned(bit, dchunk->dqc_bitmap); le32_add_cpu(&dchunk->dqc_free, 1); unlock_buffer(qbh); ocfs2_journal_dirty(handle, qbh); out_commit: mutex_unlock(&sb_dqopt(sb)->dqio_mutex); ocfs2_commit_trans(OCFS2_SB(sb), handle); out_drop_lock: ocfs2_unlock_global_qf(oinfo, 1); out_put_dquot: dqput(dquot); out_put_bh: brelse(qbh); if (status < 0) break; } brelse(hbh); list_del(&rchunk->rc_list); kfree(rchunk->rc_bitmap); kfree(rchunk); if (status < 0) break; } if (status < 0) free_recovery_list(&(rec->r_list[type])); if (status) mlog_errno(status); return status; }

Contributors

PersonTokensPropCommitsCommitProp
jan karajan kara60894.85%327.27%
joel beckerjoel becker162.50%327.27%
eric w. biedermaneric w. biederman81.25%19.09%
tao matao ma60.94%218.18%
akinobu mitaakinobu mita30.47%218.18%
Total641100.00%11100.00%

/* Recover local quota files for given node different from us */
int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, struct ocfs2_quota_recovery *rec, int slot_num) { unsigned int ino[OCFS2_MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, LOCAL_GROUP_QUOTA_SYSTEM_INODE }; struct super_block *sb = osb->sb; struct ocfs2_local_disk_dqinfo *ldinfo; struct buffer_head *bh; handle_t *handle; int type; int status = 0; struct inode *lqinode; unsigned int flags; printk(KERN_NOTICE "ocfs2: Finishing quota recovery on device (%s) for " "slot %u\n", osb->dev_str, slot_num); down_read(&sb->s_umount)