lcnalloc.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,002 行 · 第 1/3 页

C
1,002
字号
			bmp_pos = zone_start;			if (zone_start == zone_end) {				ntfs_debug("Empty zone, going to "						"done_zones_check.");				/* Empty zone. Don't bother searching it. */				goto done_zones_check;			}			ntfs_debug("Continuing outer while loop.");			continue;		} /* done_zones == 7 */		ntfs_debug("All zones are finished.");		/*		 * All zones are finished!  If DATA_ZONE, shrink mft zone.  If		 * MFT_ZONE, we have really run out of space.		 */		mft_zone_size = vol->mft_zone_end - vol->mft_zone_start;		ntfs_debug("vol->mft_zone_start 0x%llx, vol->mft_zone_end "				"0x%llx, mft_zone_size 0x%llx.",				(unsigned long long)vol->mft_zone_start,				(unsigned long long)vol->mft_zone_end,				(unsigned long long)mft_zone_size);		if (zone == MFT_ZONE || mft_zone_size <= 0) {			ntfs_debug("No free clusters left, going to out.");			/* Really no more space left on device. */			err = ENOSPC;			goto out;		} /* zone == DATA_ZONE && mft_zone_size > 0 */		ntfs_debug("Shrinking mft zone.");		zone_end = vol->mft_zone_end;		mft_zone_size >>= 1;		if (mft_zone_size > 0)			vol->mft_zone_end = vol->mft_zone_start + mft_zone_size;		else /* mft zone and data2 zone no longer exist. */			vol->data2_zone_pos = vol->mft_zone_start =					vol->mft_zone_end = 0;		if (vol->mft_zone_pos >= vol->mft_zone_end) {			vol->mft_zone_pos = vol->mft_lcn;			if (!vol->mft_zone_end)				vol->mft_zone_pos = 0;		}		bmp_pos = zone_start = bmp_initial_pos =				vol->data1_zone_pos = vol->mft_zone_end;		search_zone = 2;		pass = 2;		done_zones &= ~2;		ntfs_debug("After shrinking mft zone, mft_zone_size 0x%llx, "				"vol->mft_zone_start 0x%llx, "				"vol->mft_zone_end 0x%llx, "				"vol->mft_zone_pos 0x%llx, search_zone 2, "				"pass 2, dones_zones 0x%x, zone_start 0x%llx, "				"zone_end 0x%llx, vol->data1_zone_pos 0x%llx, "				"continuing outer while loop.",				(unsigned long long)mft_zone_size,				(unsigned long long)vol->mft_zone_start,				(unsigned long long)vol->mft_zone_end,				(unsigned long long)vol->mft_zone_pos,				done_zones, (unsigned long long)zone_start,				(unsigned long long)zone_end,				(unsigned long long)vol->data1_zone_pos);	}	ntfs_debug("After outer while loop.");out:	ntfs_debug("At out.");	/* Add runlist terminator element. */	if (likely(rl)) {		rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;		rl[rlpos].lcn = LCN_RL_NOT_MAPPED;		rl[rlpos].length = 0;	}	if (likely(page && !IS_ERR(page))) {		if (need_writeback) {			ntfs_debug("Marking page dirty.");			flush_dcache_page(page);			set_page_dirty(page);			need_writeback = 0;		}		ntfs_unmap_page(page);	}	if (likely(!err)) {		up_write(&vol->lcnbmp_lock);		ntfs_debug("Done.");		return rl;	}	ntfs_error(vol->sb, "Failed to allocate clusters, aborting "			"(error %i).", err);	if (rl) {		int err2;		if (err == ENOSPC)			ntfs_debug("Not enough space to complete allocation, "					"err ENOSPC, first free lcn 0x%llx, "					"could allocate up to 0x%llx "					"clusters.",					(unsigned long long)rl[0].lcn,					(unsigned long long)count - clusters);		/* Deallocate all allocated clusters. */		ntfs_debug("Attempting rollback...");		err2 = ntfs_cluster_free_from_rl_nolock(vol, rl);		if (err2) {			ntfs_error(vol->sb, "Failed to rollback (error %i).  "					"Leaving inconsistent metadata!  "					"Unmount and run chkdsk.", err2);			NVolSetErrors(vol);		}		/* Free the runlist. */		ntfs_free(rl);	} else if (err == ENOSPC)		ntfs_debug("No space left at all, err = ENOSPC, "				"first free lcn = 0x%llx.",				(unsigned long long)vol->data1_zone_pos);	up_write(&vol->lcnbmp_lock);	return ERR_PTR(err);}/** * __ntfs_cluster_free - free clusters on an ntfs volume * @vi:		vfs inode whose runlist describes the clusters to free * @start_vcn:	vcn in the runlist of @vi at which to start freeing clusters * @count:	number of clusters to free or -1 for all clusters * @is_rollback:	if TRUE this is a rollback operation * * Free @count clusters starting at the cluster @start_vcn in the runlist * described by the vfs inode @vi. * * If @count is -1, all clusters from @start_vcn to the end of the runlist are * deallocated.  Thus, to completely free all clusters in a runlist, use * @start_vcn = 0 and @count = -1. * * @is_rollback should always be FALSE, it is for internal use to rollback * errors.  You probably want to use ntfs_cluster_free() instead. * * Note, ntfs_cluster_free() does not modify the runlist at all, so the caller * has to deal with it later. * * Return the number of deallocated clusters (not counting sparse ones) on * success and -errno on error. * * Locking: - The runlist described by @vi must be unlocked on entry and is *	      unlocked on return. *	    - This function takes the runlist lock of @vi for reading and *	      sometimes for writing and sometimes modifies the runlist. *	    - The volume lcn bitmap must be unlocked on entry and is unlocked *	      on return. *	    - This function takes the volume lcn bitmap lock for writing and *	      modifies the bitmap contents. */s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,		const BOOL is_rollback){	s64 delta, to_free, total_freed, real_freed;	ntfs_inode *ni;	ntfs_volume *vol;	struct inode *lcnbmp_vi;	runlist_element *rl;	int err;	BUG_ON(!vi);	ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count "			"0x%llx.%s", vi->i_ino, (unsigned long long)start_vcn,			(unsigned long long)count,			is_rollback ? " (rollback)" : "");	ni = NTFS_I(vi);	vol = ni->vol;	lcnbmp_vi = vol->lcnbmp_ino;	BUG_ON(!lcnbmp_vi);	BUG_ON(start_vcn < 0);	BUG_ON(count < -1);	/*	 * Lock the lcn bitmap for writing but only if not rolling back.  We	 * must hold the lock all the way including through rollback otherwise	 * rollback is not possible because once we have cleared a bit and	 * dropped the lock, anyone could have set the bit again, thus	 * allocating the cluster for another use.	 */	if (likely(!is_rollback))		down_write(&vol->lcnbmp_lock);	total_freed = real_freed = 0;	/* This returns with ni->runlist locked for reading on success. */	rl = ntfs_find_vcn(ni, start_vcn, FALSE);	if (IS_ERR(rl)) {		if (!is_rollback)			ntfs_error(vol->sb, "Failed to find first runlist "					"element (error %li), aborting.",					PTR_ERR(rl));		err = PTR_ERR(rl);		goto err_out;	}	if (unlikely(rl->lcn < (LCN)LCN_HOLE)) {		if (!is_rollback)			ntfs_error(vol->sb, "First runlist element has "					"invalid lcn, aborting.");		err = -EIO;		goto unl_err_out;	}	/* Find the starting cluster inside the run that needs freeing. */	delta = start_vcn - rl->vcn;	/* The number of clusters in this run that need freeing. */	to_free = rl->length - delta;	if (count >= 0 && to_free > count)		to_free = count;	if (likely(rl->lcn >= 0)) {		/* Do the actual freeing of the clusters in this run. */		err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn + delta,				to_free, likely(!is_rollback) ? 0 : 1);		if (unlikely(err)) {			if (!is_rollback)				ntfs_error(vol->sb, "Failed to clear first run "						"(error %i), aborting.", err);			goto unl_err_out;		}		/* We have freed @to_free real clusters. */		real_freed = to_free;	};	/* Go to the next run and adjust the number of clusters left to free. */	++rl;	if (count >= 0)		count -= to_free;	/* Keep track of the total "freed" clusters, including sparse ones. */	total_freed = to_free;	/*	 * Loop over the remaining runs, using @count as a capping value, and	 * free them.	 */	for (; rl->length && count != 0; ++rl) {		if (unlikely(rl->lcn < (LCN)LCN_HOLE)) {			VCN vcn;			/*			 * Attempt to map runlist, dropping runlist lock for			 * the duration.			 */			up_read(&ni->runlist.lock);			vcn = rl->vcn;			err = ntfs_map_runlist(ni, vcn);			if (err) {				if (!is_rollback)					ntfs_error(vol->sb, "Failed to map "							"runlist fragment.");				if (err == -EINVAL || err == -ENOENT)					err = -EIO;				goto err_out;			}			/*			 * This returns with ni->runlist locked for reading on			 * success.			 */			rl = ntfs_find_vcn(ni, vcn, FALSE);			if (IS_ERR(rl)) {				err = PTR_ERR(rl);				if (!is_rollback)					ntfs_error(vol->sb, "Failed to find "							"subsequent runlist "							"element.");				goto err_out;			}			if (unlikely(rl->lcn < (LCN)LCN_HOLE)) {				if (!is_rollback)					ntfs_error(vol->sb, "Runlist element "							"has invalid lcn "							"(0x%llx).",							(unsigned long long)							rl->lcn);				err = -EIO;				goto unl_err_out;			}		}		/* The number of clusters in this run that need freeing. */		to_free = rl->length;		if (count >= 0 && to_free > count)			to_free = count;		if (likely(rl->lcn >= 0)) {			/* Do the actual freeing of the clusters in the run. */			err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn,					to_free, likely(!is_rollback) ? 0 : 1);			if (unlikely(err)) {				if (!is_rollback)					ntfs_error(vol->sb, "Failed to clear "							"subsequent run.");				goto unl_err_out;			}			/* We have freed @to_free real clusters. */			real_freed += to_free;		}		/* Adjust the number of clusters left to free. */		if (count >= 0)			count -= to_free;			/* Update the total done clusters. */		total_freed += to_free;	}	up_read(&ni->runlist.lock);	if (likely(!is_rollback))		up_write(&vol->lcnbmp_lock);	BUG_ON(count > 0);	/* We are done.  Return the number of actually freed clusters. */	ntfs_debug("Done.");	return real_freed;unl_err_out:	up_read(&ni->runlist.lock);err_out:	if (is_rollback)		return err;	/* If no real clusters were freed, no need to rollback. */	if (!real_freed) {		up_write(&vol->lcnbmp_lock);		return err;	}	/*	 * Attempt to rollback and if that succeeds just return the error code.	 * If rollback fails, set the volume errors flag, emit an error	 * message, and return the error code.	 */	delta = __ntfs_cluster_free(vi, start_vcn, total_freed, TRUE);	if (delta < 0) {		ntfs_error(vol->sb, "Failed to rollback (error %i).  Leaving "				"inconsistent metadata!  Unmount and run "				"chkdsk.", (int)delta);		NVolSetErrors(vol);	}	up_write(&vol->lcnbmp_lock);	ntfs_error(vol->sb, "Aborting (error %i).", err);	return err;}#endif /* NTFS_RW */

⌨️ 快捷键说明

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