⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 2.6.5-quotafix.patch

📁 非常经典的一个分布式系统
💻 PATCH
📖 第 1 页 / 共 5 页
字号:
 	spin_unlock(&dq_list_lock);  	for (cnt = 0; cnt < MAXQUOTAS; cnt++)-		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt])) {-			down(&dqopt->dqio_sem);-			dqopt->ops[cnt]->write_file_info(sb, cnt);-			up(&dqopt->dqio_sem);-		}+		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) +				&& info_dirty(&dqopt->info[cnt]))+			sb->dq_op->write_info(sb, cnt); 	spin_lock(&dq_list_lock); 	dqstats.syncs++; 	spin_unlock(&dq_list_lock);@@ -432,11 +513,19 @@ we_slept: 		spin_unlock(&dq_list_lock); 		return; 	}-	if (dquot_dirty(dquot)) {+	if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && dquot_dirty(dquot)) { 		spin_unlock(&dq_list_lock); 		dquot->dq_sb->dq_op->write_dquot(dquot); 		goto we_slept; 	}+	/* Clear flag in case dquot was inactive (something bad happened) */+	test_and_clear_bit(DQ_MOD_B, &dquot->dq_flags);+	if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {+		spin_unlock(&dq_list_lock);+		dquot->dq_sb->dq_op->release_dquot(dquot);+		goto we_slept;+	}+			 	atomic_dec(&dquot->dq_count); #ifdef __DQUOT_PARANOIA 	/* sanity check */@@ -495,7 +584,6 @@ we_slept: 		insert_dquot_hash(dquot); 		dqstats.lookups++; 		spin_unlock(&dq_list_lock);-		read_dqblk(dquot); 	} else { 		if (!atomic_read(&dquot->dq_count)) 			remove_free_dquot(dquot);@@ -503,10 +591,15 @@ we_slept: 		dqstats.cache_hits++; 		dqstats.lookups++; 		spin_unlock(&dq_list_lock);-		wait_on_dquot(dquot); 		if (empty) 			kmem_cache_free(dquot_cachep, empty); 	}+	wait_on_dquot(dquot);+	/* Read the dquot and instantiate it (everything done only if needed) */+	if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && sb->dq_op->acquire_dquot(dquot) < 0) {+		dqput(dquot);+		return NODQUOT;+	}  #ifdef __DQUOT_PARANOIA 	if (!dquot->dq_sb)	/* Has somebody invalidated entry under us? */@@ -819,19 +912,19 @@ static int check_bdq(struct dquot *dquot  *  * Note: this is a blocking operation.  */-void dquot_initialize(struct inode *inode, int type)+int dquot_initialize(struct inode *inode, int type) { 	unsigned int id = 0; 	int cnt;  	/* Solve deadlock when we recurse when holding dqptr_sem... */ 	if (IS_NOQUOTA(inode))-		return;+		return 0; 	down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); 	/* Having dqptr_sem we know NOQUOTA flags can't be altered... */ 	if (IS_NOQUOTA(inode)) { 		up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);-		return;+		return 0; 	} 	/* Build list of quotas to initialize... */ 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {@@ -852,13 +945,14 @@ void dquot_initialize(struct inode *inod 		} 	} 	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);+	return 0; }  /*  * 	Release all quotas referenced by inode  *	Needs dqonoff_sem to guard dqput()  */-void dquot_drop(struct inode *inode)+int dquot_drop(struct inode *inode) { 	int cnt; @@ -871,6 +965,7 @@ void dquot_drop(struct inode *inode) 		} 	} 	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);+	return 0; }  /*@@ -958,14 +1053,14 @@ warn_put_all: /*  * This is a non-blocking operation.  */-void dquot_free_space(struct inode *inode, qsize_t number)+int dquot_free_space(struct inode *inode, qsize_t number) { 	unsigned int cnt;  	/* Solve deadlock when we recurse when holding dqptr_sem... */ 	if (IS_NOQUOTA(inode)) { 		inode_add_bytes(inode, number);-		return;+		return QUOTA_OK; 	} 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 	spin_lock(&dq_data_lock);@@ -981,23 +1076,24 @@ sub_bytes: 	inode_sub_bytes(inode, number); 	spin_unlock(&dq_data_lock); 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);+	return QUOTA_OK; }  /*  * This is a non-blocking operation.  */-void dquot_free_inode(const struct inode *inode, unsigned long number)+int dquot_free_inode(const struct inode *inode, unsigned long number) { 	unsigned int cnt;  	/* Solve deadlock when we recurse when holding dqptr_sem... */ 	if (IS_NOQUOTA(inode))-		return;+		return QUOTA_OK; 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 	/* Now recheck reliably when holding dqptr_sem */ 	if (IS_NOQUOTA(inode)) { 		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);-		return;+		return QUOTA_OK; 	} 	spin_lock(&dq_data_lock); 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {@@ -1007,6 +1103,7 @@ void dquot_free_inode(const struct inode 	} 	spin_unlock(&dq_data_lock); 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);+	return QUOTA_OK; }  /*@@ -1104,6 +1201,20 @@ warn_put_all: }  /*+ * Write info of quota file to disk+ */+int dquot_commit_info(struct super_block *sb, int type)+{+	int ret;+	struct quota_info *dqopt = sb_dqopt(sb);++	down(&dqopt->dqio_sem);+	ret = dqopt->ops[type]->write_file_info(sb, type);+	up(&dqopt->dqio_sem);+	return ret;+}++/*  * Definitions of diskquota operations.  */ struct dquot_operations dquot_operations = {@@ -1114,7 +1225,10 @@ struct dquot_operations dquot_operations 	.free_space	= dquot_free_space, 	.free_inode	= dquot_free_inode, 	.transfer	= dquot_transfer,-	.write_dquot	= commit_dqblk+	.write_dquot	= dquot_commit,+	.acquire_dquot  = dquot_acquire,+	.release_dquot	= dquot_release,+	.write_info     = dquot_commit_info				 };  /* Function used by filesystems for initializing the dquot_operations structure */@@ -1154,13 +1268,14 @@ int vfs_quota_off(struct super_block *sb { 	int cnt; 	struct quota_info *dqopt = sb_dqopt(sb);--	if (!sb)-		goto out;+	struct inode *toputinode[MAXQUOTAS];+	struct vfsmount *toputmnt[MAXQUOTAS];  	/* We need to serialize quota_off() for device */ 	down(&dqopt->dqonoff_sem); 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {+		toputinode[cnt] = NULL;+		toputmnt[cnt] = NULL; 		if (type != -1 && cnt != type) 			continue; 		if (!sb_has_quota_enabled(sb, cnt))@@ -1172,94 +1287,115 @@ int vfs_quota_off(struct super_block *sb 		invalidate_dquots(sb, cnt); 		/* 		 * Now all dquots should be invalidated, all writes done so we should be only-		 * users of the info. No locks needed.+		 * users of the info. 		 */-		if (info_dirty(&dqopt->info[cnt])) {-			down(&dqopt->dqio_sem);-			dqopt->ops[cnt]->write_file_info(sb, cnt);-			up(&dqopt->dqio_sem);-		}+		if (info_dirty(&dqopt->info[cnt]))+			sb->dq_op->write_info(sb, cnt); 		if (dqopt->ops[cnt]->free_file_info) 			dqopt->ops[cnt]->free_file_info(sb, cnt); 		put_quota_format(dqopt->info[cnt].dqi_format); -		fput(dqopt->files[cnt]);-		dqopt->files[cnt] = (struct file *)NULL;+		toputinode[cnt] = dqopt->files[cnt];+		toputmnt[cnt] = dqopt->mnt[cnt];+		dqopt->files[cnt] = NULL;+		dqopt->mnt[cnt] = NULL; 		dqopt->info[cnt].dqi_flags = 0; 		dqopt->info[cnt].dqi_igrace = 0; 		dqopt->info[cnt].dqi_bgrace = 0; 		dqopt->ops[cnt] = NULL; 	} 	up(&dqopt->dqonoff_sem);-out:+	/* Sync the superblock so that buffers with quota data are written to+	 * disk (and so userspace sees correct data afterwards).+	 * The reference to vfsmnt we are still holding protects us from+	 * umount (we don't have it only when quotas are turned on/off for+	 * journal replay but in that case we are guarded by the fs anyway). */+	if (sb->s_op->sync_fs)+		sb->s_op->sync_fs(sb, 1);+	sync_blockdev(sb->s_bdev);+	/* Now the quota files are just ordinary files and we can set the+	 * inode flags back. Moreover we discard the pagecache so that+	 * userspace sees the writes we did bypassing the pagecache. We+	 * must also discard the blockdev buffers so that we see the+	 * changes done by userspace on the next quotaon() */+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)+		if (toputinode[cnt]) {+			down(&dqopt->dqonoff_sem);+			/* If quota was reenabled in the meantime, we have+			 * nothing to do */+			if (!sb_has_quota_enabled(sb, cnt)) {+				down(&toputinode[cnt]->i_sem);+				toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |+				  S_NOATIME | S_NOQUOTA);+				truncate_inode_pages(&toputinode[cnt]->i_data, 0);+				up(&toputinode[cnt]->i_sem);+				mark_inode_dirty(toputinode[cnt]);+				iput(toputinode[cnt]);+			}+			up(&dqopt->dqonoff_sem);+			/* We don't hold the reference when we turned on quotas+			 * just for the journal replay... */+			if (toputmnt[cnt])+				mntput(toputmnt[cnt]);+		}+	invalidate_bdev(sb->s_bdev, 0); 	return 0; } -int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)+/*+ *	Turn quotas on on a device+ */++/* Helper function when we already have the inode */+static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) {-	struct file *f;-	struct inode *inode;-	struct quota_info *dqopt = sb_dqopt(sb); 	struct quota_format_type *fmt = find_quota_format(format_id);-	int error, cnt;-	struct dquot *to_drop[MAXQUOTAS];-	unsigned int oldflags;+	struct super_block *sb = inode->i_sb;+	struct quota_info *dqopt = sb_dqopt(sb);+	int error;+	int oldflags = -1;  	if (!fmt) 		return -ESRCH;-	f = filp_open(path, O_RDWR, 0600);-	if (IS_ERR(f)) {-		error = PTR_ERR(f);+	if (!S_ISREG(inode->i_mode)) {+		error = -EACCES;+		goto out_fmt;+	}+	if (IS_RDONLY(inode)) {+		error = -EROFS;+		goto out_fmt;+	}+	if (!sb->s_op->quota_write || !sb->s_op->quota_read) {+		error = -EINVAL; 		goto out_fmt; 	}-	error = -EIO;-	if (!f->f_op || !f->f_op->read || !f->f_op->write)-		goto out_f;-	error = security_quota_on(f);-	if (error)-		goto out_f;-	inode = f->f_dentry->d_inode;-	error = -EACCES;-	if (!S_ISREG(inode->i_mode))-		goto out_f; +	/* As we bypass the pagecache we must now flush the inode so that+	 * we see all the changes from userspace... */+	write_inode_now(inode, 1);+	/* And now flush the block cache so that kernel sees the changes */+	invalidate_bdev(sb->s_bdev, 0);+	down(&inode->i_sem); 	down(&dqopt->dqonoff_sem); 	if (sb_has_quota_enabled(sb, type)) { 		error = -EBUSY; 		goto out_lock; 	}-	oldflags = inode->i_flags;-	dqopt->files[type] = f;-	error = -EINVAL;-	if (!fmt->qf_ops->check_quota_file(sb, type))-		goto out_file_init; 	/* We don't want quota and atime on quota files (deadlocks possible)-	 * We also need to set GFP mask differently because we cannot recurse-	 * into filesystem when allocating page for quota inode */+	 * Also nobody should write to the file - we use special IO operations+	 * which ignore the immutable bit. */ 	down_write(&dqopt->dqptr_sem);-	inode->i_flags |= S_NOQUOTA | S_NOATIME;--	/*-	 * We write to quota files deep within filesystem code.  We don't want-	 * the VFS to reenter filesystem code when it tries to allocate a-	 * pagecache page for the quota file write.  So clear __GFP_FS in-	 * the quota file's allocation flags.-	 */-	mapping_set_gfp_mask(inode->i_mapping,-		mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);--	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {-		to_drop[cnt] = inode->i_dquot[cnt];-		inode->i_dquot[cnt] = NODQUOT;-	}-	inode->i_flags &= ~S_QUOTA;+	oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | S_NOQUOTA);+	inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE; 	up_write(&dqopt->dqptr_sem);-	/* We must put dquots outside of dqptr_sem because we may need to-	 * start transaction for write */-	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {-		if (to_drop[cnt])-			dqput(to_drop[cnt]);-	}++	error = -EIO;+	dqopt->files[type] = igrab(inode);+	if (!dqopt->files[type])+		goto out_lock;+	error = -EINVAL;+	if (!fmt->qf_ops->check_quota_file(sb, type))+		goto out_file_init;  	dqopt->ops[type] = fmt->qf_ops; 	dqopt->info[type].dqi_format = fmt;@@ -1269,6 +1405,7 @@ int vfs_quota_on(struct super_block *sb, 		goto out_file_init; 	} 	up(&dqopt->dqio_sem);+	up(&inode->i_sem); 	set_enable_flags(dqopt, type);  	add_dquot_ref(sb, type);@@ -1277,18 +1414,51 @@ int vfs_quota_on(struct super_block *sb, 	return 0;  out_file_init:-	inode->i_flags = oldflags;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -