1987da915Sopenharmony_ci/**
2987da915Sopenharmony_ci * lcnalloc.c - Cluster (de)allocation code. Originated from the Linux-NTFS project.
3987da915Sopenharmony_ci *
4987da915Sopenharmony_ci * Copyright (c) 2002-2004 Anton Altaparmakov
5987da915Sopenharmony_ci * Copyright (c) 2004 Yura Pakhuchiy
6987da915Sopenharmony_ci * Copyright (c) 2004-2008 Szabolcs Szakacsits
7987da915Sopenharmony_ci * Copyright (c) 2008-2009 Jean-Pierre Andre
8987da915Sopenharmony_ci *
9987da915Sopenharmony_ci * This program/include file is free software; you can redistribute it and/or
10987da915Sopenharmony_ci * modify it under the terms of the GNU General Public License as published
11987da915Sopenharmony_ci * by the Free Software Foundation; either version 2 of the License, or
12987da915Sopenharmony_ci * (at your option) any later version.
13987da915Sopenharmony_ci *
14987da915Sopenharmony_ci * This program/include file is distributed in the hope that it will be
15987da915Sopenharmony_ci * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16987da915Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17987da915Sopenharmony_ci * GNU General Public License for more details.
18987da915Sopenharmony_ci *
19987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License
20987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G
21987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software
22987da915Sopenharmony_ci * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23987da915Sopenharmony_ci */
24987da915Sopenharmony_ci
25987da915Sopenharmony_ci#ifdef HAVE_CONFIG_H
26987da915Sopenharmony_ci#include "config.h"
27987da915Sopenharmony_ci#endif
28987da915Sopenharmony_ci
29987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H
30987da915Sopenharmony_ci#include <stdlib.h>
31987da915Sopenharmony_ci#endif
32987da915Sopenharmony_ci#ifdef HAVE_STDIO_H
33987da915Sopenharmony_ci#include <stdio.h>
34987da915Sopenharmony_ci#endif
35987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H
36987da915Sopenharmony_ci#include <errno.h>
37987da915Sopenharmony_ci#endif
38987da915Sopenharmony_ci
39987da915Sopenharmony_ci#include "types.h"
40987da915Sopenharmony_ci#include "attrib.h"
41987da915Sopenharmony_ci#include "bitmap.h"
42987da915Sopenharmony_ci#include "debug.h"
43987da915Sopenharmony_ci#include "runlist.h"
44987da915Sopenharmony_ci#include "volume.h"
45987da915Sopenharmony_ci#include "lcnalloc.h"
46987da915Sopenharmony_ci#include "logging.h"
47987da915Sopenharmony_ci#include "misc.h"
48987da915Sopenharmony_ci
49987da915Sopenharmony_ci/*
50987da915Sopenharmony_ci * Plenty possibilities for big optimizations all over in the cluster
51987da915Sopenharmony_ci * allocation, however at the moment the dominant bottleneck (~ 90%) is
52987da915Sopenharmony_ci * the update of the mapping pairs which converges to the cubic Faulhaber's
53987da915Sopenharmony_ci * formula as the function of the number of extents (fragments, runs).
54987da915Sopenharmony_ci */
55987da915Sopenharmony_ci#define NTFS_LCNALLOC_BSIZE 4096
56987da915Sopenharmony_ci#define NTFS_LCNALLOC_SKIP  NTFS_LCNALLOC_BSIZE
57987da915Sopenharmony_ci
58987da915Sopenharmony_cienum {
59987da915Sopenharmony_ci	ZONE_MFT = 1,
60987da915Sopenharmony_ci	ZONE_DATA1 = 2,
61987da915Sopenharmony_ci	ZONE_DATA2 = 4
62987da915Sopenharmony_ci} ;
63987da915Sopenharmony_ci
64987da915Sopenharmony_cistatic void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc)
65987da915Sopenharmony_ci{
66987da915Sopenharmony_ci	ntfs_log_trace("pos: %lld  tc: %lld\n", (long long)*pos, (long long)tc);
67987da915Sopenharmony_ci
68987da915Sopenharmony_ci	if (tc >= end)
69987da915Sopenharmony_ci		*pos = start;
70987da915Sopenharmony_ci	else if (tc >= start)
71987da915Sopenharmony_ci		*pos = tc;
72987da915Sopenharmony_ci}
73987da915Sopenharmony_ci
74987da915Sopenharmony_cistatic void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc)
75987da915Sopenharmony_ci{
76987da915Sopenharmony_ci	ntfs_log_trace("tc = %lld, zone = %d\n", (long long)tc, zone);
77987da915Sopenharmony_ci
78987da915Sopenharmony_ci	if (zone == ZONE_MFT)
79987da915Sopenharmony_ci		ntfs_cluster_set_zone_pos(vol->mft_lcn, vol->mft_zone_end,
80987da915Sopenharmony_ci					  &vol->mft_zone_pos, tc);
81987da915Sopenharmony_ci	else if (zone == ZONE_DATA1)
82987da915Sopenharmony_ci		ntfs_cluster_set_zone_pos(vol->mft_zone_end, vol->nr_clusters,
83987da915Sopenharmony_ci					  &vol->data1_zone_pos, tc);
84987da915Sopenharmony_ci	else /* zone == ZONE_DATA2 */
85987da915Sopenharmony_ci		ntfs_cluster_set_zone_pos(0, vol->mft_zone_start,
86987da915Sopenharmony_ci					  &vol->data2_zone_pos, tc);
87987da915Sopenharmony_ci}
88987da915Sopenharmony_ci
89987da915Sopenharmony_ci/*
90987da915Sopenharmony_ci *		Unmark full zones when a cluster has been freed in a full zone
91987da915Sopenharmony_ci *
92987da915Sopenharmony_ci *	Next allocation will reuse the freed cluster
93987da915Sopenharmony_ci */
94987da915Sopenharmony_ci
95987da915Sopenharmony_cistatic void update_full_status(ntfs_volume *vol, LCN lcn)
96987da915Sopenharmony_ci{
97987da915Sopenharmony_ci	if (lcn >= vol->mft_zone_end) {
98987da915Sopenharmony_ci		if (vol->full_zones & ZONE_DATA1) {
99987da915Sopenharmony_ci			ntfs_cluster_update_zone_pos(vol, ZONE_DATA1, lcn);
100987da915Sopenharmony_ci			vol->full_zones &= ~ZONE_DATA1;
101987da915Sopenharmony_ci		}
102987da915Sopenharmony_ci	} else
103987da915Sopenharmony_ci		if (lcn < vol->mft_zone_start) {
104987da915Sopenharmony_ci			if (vol->full_zones & ZONE_DATA2) {
105987da915Sopenharmony_ci				ntfs_cluster_update_zone_pos(vol, ZONE_DATA2, lcn);
106987da915Sopenharmony_ci				vol->full_zones &= ~ZONE_DATA2;
107987da915Sopenharmony_ci			}
108987da915Sopenharmony_ci		} else {
109987da915Sopenharmony_ci			if (vol->full_zones & ZONE_MFT) {
110987da915Sopenharmony_ci				ntfs_cluster_update_zone_pos(vol, ZONE_MFT, lcn);
111987da915Sopenharmony_ci				vol->full_zones &= ~ZONE_MFT;
112987da915Sopenharmony_ci			}
113987da915Sopenharmony_ci		}
114987da915Sopenharmony_ci}
115987da915Sopenharmony_ci
116987da915Sopenharmony_cistatic s64 max_empty_bit_range(unsigned char *buf, int size)
117987da915Sopenharmony_ci{
118987da915Sopenharmony_ci	int i, j, run = 0;
119987da915Sopenharmony_ci	int max_range = 0;
120987da915Sopenharmony_ci	s64 start_pos = -1;
121987da915Sopenharmony_ci
122987da915Sopenharmony_ci	ntfs_log_trace("Entering\n");
123987da915Sopenharmony_ci
124987da915Sopenharmony_ci	i = 0;
125987da915Sopenharmony_ci	while (i < size) {
126987da915Sopenharmony_ci		switch (*buf) {
127987da915Sopenharmony_ci		case 0 :
128987da915Sopenharmony_ci			do {
129987da915Sopenharmony_ci				buf++;
130987da915Sopenharmony_ci				run += 8;
131987da915Sopenharmony_ci				i++;
132987da915Sopenharmony_ci			} while ((i < size) && !*buf);
133987da915Sopenharmony_ci			break;
134987da915Sopenharmony_ci		case 255 :
135987da915Sopenharmony_ci			if (run > max_range) {
136987da915Sopenharmony_ci				max_range = run;
137987da915Sopenharmony_ci				start_pos = (s64)i * 8 - run;
138987da915Sopenharmony_ci			}
139987da915Sopenharmony_ci			run = 0;
140987da915Sopenharmony_ci			do {
141987da915Sopenharmony_ci				buf++;
142987da915Sopenharmony_ci				i++;
143987da915Sopenharmony_ci			} while ((i < size) && (*buf == 255));
144987da915Sopenharmony_ci			break;
145987da915Sopenharmony_ci		default :
146987da915Sopenharmony_ci			for (j = 0; j < 8; j++) {
147987da915Sopenharmony_ci
148987da915Sopenharmony_ci				int bit = *buf & (1 << j);
149987da915Sopenharmony_ci
150987da915Sopenharmony_ci				if (bit) {
151987da915Sopenharmony_ci					if (run > max_range) {
152987da915Sopenharmony_ci						max_range = run;
153987da915Sopenharmony_ci						start_pos = (s64)i * 8 + (j - run);
154987da915Sopenharmony_ci					}
155987da915Sopenharmony_ci					run = 0;
156987da915Sopenharmony_ci				} else
157987da915Sopenharmony_ci					run++;
158987da915Sopenharmony_ci			}
159987da915Sopenharmony_ci			i++;
160987da915Sopenharmony_ci			buf++;
161987da915Sopenharmony_ci
162987da915Sopenharmony_ci		}
163987da915Sopenharmony_ci	}
164987da915Sopenharmony_ci
165987da915Sopenharmony_ci	if (run > max_range)
166987da915Sopenharmony_ci		start_pos = (s64)i * 8 - run;
167987da915Sopenharmony_ci
168987da915Sopenharmony_ci	return start_pos;
169987da915Sopenharmony_ci}
170987da915Sopenharmony_ci
171987da915Sopenharmony_cistatic int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
172987da915Sopenharmony_ci			    u8 *writeback)
173987da915Sopenharmony_ci{
174987da915Sopenharmony_ci	s64 written;
175987da915Sopenharmony_ci
176987da915Sopenharmony_ci	ntfs_log_trace("Entering\n");
177987da915Sopenharmony_ci
178987da915Sopenharmony_ci	if (!*writeback)
179987da915Sopenharmony_ci		return 0;
180987da915Sopenharmony_ci
181987da915Sopenharmony_ci	*writeback = 0;
182987da915Sopenharmony_ci
183987da915Sopenharmony_ci	written = ntfs_attr_pwrite(vol->lcnbmp_na, pos, size, b);
184987da915Sopenharmony_ci	if (written != size) {
185987da915Sopenharmony_ci		if (!written)
186987da915Sopenharmony_ci			errno = EIO;
187987da915Sopenharmony_ci		ntfs_log_perror("Bitmap write error (%lld, %lld)",
188987da915Sopenharmony_ci				(long long)pos, (long long)size);
189987da915Sopenharmony_ci		return -1;
190987da915Sopenharmony_ci	}
191987da915Sopenharmony_ci
192987da915Sopenharmony_ci	return 0;
193987da915Sopenharmony_ci}
194987da915Sopenharmony_ci
195987da915Sopenharmony_ci/**
196987da915Sopenharmony_ci * ntfs_cluster_alloc - allocate clusters on an ntfs volume
197987da915Sopenharmony_ci * @vol:	mounted ntfs volume on which to allocate the clusters
198987da915Sopenharmony_ci * @start_vcn:	vcn to use for the first allocated cluster
199987da915Sopenharmony_ci * @count:	number of clusters to allocate
200987da915Sopenharmony_ci * @start_lcn:	starting lcn at which to allocate the clusters (or -1 if none)
201987da915Sopenharmony_ci * @zone:	zone from which to allocate the clusters
202987da915Sopenharmony_ci *
203987da915Sopenharmony_ci * Allocate @count clusters preferably starting at cluster @start_lcn or at the
204987da915Sopenharmony_ci * current allocator position if @start_lcn is -1, on the mounted ntfs volume
205987da915Sopenharmony_ci * @vol. @zone is either DATA_ZONE for allocation of normal clusters and
206987da915Sopenharmony_ci * MFT_ZONE for allocation of clusters for the master file table, i.e. the
207987da915Sopenharmony_ci * $MFT/$DATA attribute.
208987da915Sopenharmony_ci *
209987da915Sopenharmony_ci * On success return a runlist describing the allocated cluster(s).
210987da915Sopenharmony_ci *
211987da915Sopenharmony_ci * On error return NULL with errno set to the error code.
212987da915Sopenharmony_ci *
213987da915Sopenharmony_ci * Notes on the allocation algorithm
214987da915Sopenharmony_ci * =================================
215987da915Sopenharmony_ci *
216987da915Sopenharmony_ci * There are two data zones. First is the area between the end of the mft zone
217987da915Sopenharmony_ci * and the end of the volume, and second is the area between the start of the
218987da915Sopenharmony_ci * volume and the start of the mft zone. On unmodified/standard NTFS 1.x
219987da915Sopenharmony_ci * volumes, the second data zone doesn't exist due to the mft zone being
220987da915Sopenharmony_ci * expanded to cover the start of the volume in order to reserve space for the
221987da915Sopenharmony_ci * mft bitmap attribute.
222987da915Sopenharmony_ci *
223987da915Sopenharmony_ci * The complexity stems from the need of implementing the mft vs data zoned
224987da915Sopenharmony_ci * approach and from the fact that we have access to the lcn bitmap via up to
225987da915Sopenharmony_ci * NTFS_LCNALLOC_BSIZE bytes at a time, so we need to cope with crossing over
226987da915Sopenharmony_ci * boundaries of two buffers. Further, the fact that the allocator allows for
227987da915Sopenharmony_ci * caller supplied hints as to the location of where allocation should begin
228987da915Sopenharmony_ci * and the fact that the allocator keeps track of where in the data zones the
229987da915Sopenharmony_ci * next natural allocation should occur, contribute to the complexity of the
230987da915Sopenharmony_ci * function. But it should all be worthwhile, because this allocator:
231987da915Sopenharmony_ci *   1) implements MFT zone reservation
232987da915Sopenharmony_ci *   2) causes reduction in fragmentation.
233987da915Sopenharmony_ci * The code is not optimized for speed.
234987da915Sopenharmony_ci */
235987da915Sopenharmony_cirunlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
236987da915Sopenharmony_ci		LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone)
237987da915Sopenharmony_ci{
238987da915Sopenharmony_ci	LCN zone_start, zone_end;  /* current search range */
239987da915Sopenharmony_ci	LCN last_read_pos, lcn;
240987da915Sopenharmony_ci	LCN bmp_pos;		/* current bit position inside the bitmap */
241987da915Sopenharmony_ci	LCN prev_lcn = 0, prev_run_len = 0;
242987da915Sopenharmony_ci	s64 clusters, br;
243987da915Sopenharmony_ci	runlist *rl = NULL, *trl;
244987da915Sopenharmony_ci	u8 *buf, *byte, bit, writeback;
245987da915Sopenharmony_ci	u8 pass = 1; 	/* 1: inside zone;  2: start of zone */
246987da915Sopenharmony_ci	u8 search_zone; /* 4: data2 (start) 1: mft (middle) 2: data1 (end) */
247987da915Sopenharmony_ci	u8 done_zones = 0;
248987da915Sopenharmony_ci	u8 has_guess, used_zone_pos;
249987da915Sopenharmony_ci	int err = 0, rlpos, rlsize, buf_size;
250987da915Sopenharmony_ci
251987da915Sopenharmony_ci	ntfs_log_enter("Entering with count = 0x%llx, start_lcn = 0x%llx, "
252987da915Sopenharmony_ci		       "zone = %s_ZONE.\n", (long long)count, (long long)
253987da915Sopenharmony_ci		       start_lcn, zone == MFT_ZONE ? "MFT" : "DATA");
254987da915Sopenharmony_ci
255987da915Sopenharmony_ci	if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
256987da915Sopenharmony_ci			(s8)zone < FIRST_ZONE || zone > LAST_ZONE) {
257987da915Sopenharmony_ci		errno = EINVAL;
258987da915Sopenharmony_ci		ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld",
259987da915Sopenharmony_ci				__FUNCTION__, (long long)start_vcn,
260987da915Sopenharmony_ci				(long long)count, (long long)start_lcn);
261987da915Sopenharmony_ci		goto out;
262987da915Sopenharmony_ci	}
263987da915Sopenharmony_ci
264987da915Sopenharmony_ci	/* Return empty runlist if @count == 0 */
265987da915Sopenharmony_ci	if (!count) {
266987da915Sopenharmony_ci		rl = ntfs_malloc(0x1000);
267987da915Sopenharmony_ci		if (rl) {
268987da915Sopenharmony_ci			rl[0].vcn = start_vcn;
269987da915Sopenharmony_ci			rl[0].lcn = LCN_RL_NOT_MAPPED;
270987da915Sopenharmony_ci			rl[0].length = 0;
271987da915Sopenharmony_ci		}
272987da915Sopenharmony_ci		goto out;
273987da915Sopenharmony_ci	}
274987da915Sopenharmony_ci
275987da915Sopenharmony_ci	buf = ntfs_malloc(NTFS_LCNALLOC_BSIZE);
276987da915Sopenharmony_ci	if (!buf)
277987da915Sopenharmony_ci		goto out;
278987da915Sopenharmony_ci	/*
279987da915Sopenharmony_ci	 * If no @start_lcn was requested, use the current zone
280987da915Sopenharmony_ci	 * position otherwise use the requested @start_lcn.
281987da915Sopenharmony_ci	 */
282987da915Sopenharmony_ci	has_guess = 1;
283987da915Sopenharmony_ci	zone_start = start_lcn;
284987da915Sopenharmony_ci
285987da915Sopenharmony_ci	if (zone_start < 0) {
286987da915Sopenharmony_ci		if (zone == DATA_ZONE)
287987da915Sopenharmony_ci			zone_start = vol->data1_zone_pos;
288987da915Sopenharmony_ci		else
289987da915Sopenharmony_ci			zone_start = vol->mft_zone_pos;
290987da915Sopenharmony_ci		has_guess = 0;
291987da915Sopenharmony_ci	}
292987da915Sopenharmony_ci
293987da915Sopenharmony_ci	used_zone_pos = has_guess ? 0 : 1;
294987da915Sopenharmony_ci
295987da915Sopenharmony_ci	if (!zone_start || zone_start == vol->mft_zone_start ||
296987da915Sopenharmony_ci			zone_start == vol->mft_zone_end)
297987da915Sopenharmony_ci		pass = 2;
298987da915Sopenharmony_ci
299987da915Sopenharmony_ci	if (zone_start < vol->mft_zone_start) {
300987da915Sopenharmony_ci		zone_end = vol->mft_zone_start;
301987da915Sopenharmony_ci		search_zone = ZONE_DATA2;
302987da915Sopenharmony_ci	} else if (zone_start < vol->mft_zone_end) {
303987da915Sopenharmony_ci		zone_end = vol->mft_zone_end;
304987da915Sopenharmony_ci		search_zone = ZONE_MFT;
305987da915Sopenharmony_ci	} else {
306987da915Sopenharmony_ci		zone_end = vol->nr_clusters;
307987da915Sopenharmony_ci		search_zone = ZONE_DATA1;
308987da915Sopenharmony_ci	}
309987da915Sopenharmony_ci
310987da915Sopenharmony_ci	bmp_pos = zone_start;
311987da915Sopenharmony_ci
312987da915Sopenharmony_ci	/* Loop until all clusters are allocated. */
313987da915Sopenharmony_ci	clusters = count;
314987da915Sopenharmony_ci	rlpos = rlsize = 0;
315987da915Sopenharmony_ci	while (1) {
316987da915Sopenharmony_ci			/* check whether we have exhausted the current zone */
317987da915Sopenharmony_ci		if (search_zone & vol->full_zones)
318987da915Sopenharmony_ci			goto zone_pass_done;
319987da915Sopenharmony_ci		last_read_pos = bmp_pos >> 3;
320987da915Sopenharmony_ci		br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos,
321987da915Sopenharmony_ci				     NTFS_LCNALLOC_BSIZE, buf);
322987da915Sopenharmony_ci		if (br <= 0) {
323987da915Sopenharmony_ci			if (!br)
324987da915Sopenharmony_ci				goto zone_pass_done;
325987da915Sopenharmony_ci			err = errno;
326987da915Sopenharmony_ci			ntfs_log_perror("Reading $BITMAP failed");
327987da915Sopenharmony_ci			goto err_ret;
328987da915Sopenharmony_ci		}
329987da915Sopenharmony_ci		/*
330987da915Sopenharmony_ci		 * We might have read less than NTFS_LCNALLOC_BSIZE bytes
331987da915Sopenharmony_ci		 * if we are close to the end of the attribute.
332987da915Sopenharmony_ci		 */
333987da915Sopenharmony_ci		buf_size = (int)br << 3;
334987da915Sopenharmony_ci		lcn = bmp_pos & 7;
335987da915Sopenharmony_ci		bmp_pos &= ~7;
336987da915Sopenharmony_ci		writeback = 0;
337987da915Sopenharmony_ci
338987da915Sopenharmony_ci		while (lcn < buf_size) {
339987da915Sopenharmony_ci			byte = buf + (lcn >> 3);
340987da915Sopenharmony_ci			bit = 1 << (lcn & 7);
341987da915Sopenharmony_ci			if (has_guess) {
342987da915Sopenharmony_ci				if (*byte & bit) {
343987da915Sopenharmony_ci					has_guess = 0;
344987da915Sopenharmony_ci					break;
345987da915Sopenharmony_ci				}
346987da915Sopenharmony_ci			} else {
347987da915Sopenharmony_ci				lcn = max_empty_bit_range(buf, br);
348987da915Sopenharmony_ci				if (lcn < 0)
349987da915Sopenharmony_ci					break;
350987da915Sopenharmony_ci				has_guess = 1;
351987da915Sopenharmony_ci				continue;
352987da915Sopenharmony_ci			}
353987da915Sopenharmony_ci
354987da915Sopenharmony_ci			/* First free bit is at lcn + bmp_pos. */
355987da915Sopenharmony_ci
356987da915Sopenharmony_ci			/* Reallocate memory if necessary. */
357987da915Sopenharmony_ci			if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) {
358987da915Sopenharmony_ci				rlsize += 4096;
359987da915Sopenharmony_ci				trl = realloc(rl, rlsize);
360987da915Sopenharmony_ci				if (!trl) {
361987da915Sopenharmony_ci					err = ENOMEM;
362987da915Sopenharmony_ci					ntfs_log_perror("realloc() failed");
363987da915Sopenharmony_ci					goto wb_err_ret;
364987da915Sopenharmony_ci				}
365987da915Sopenharmony_ci				rl = trl;
366987da915Sopenharmony_ci			}
367987da915Sopenharmony_ci
368987da915Sopenharmony_ci			/* Allocate the bitmap bit. */
369987da915Sopenharmony_ci			*byte |= bit;
370987da915Sopenharmony_ci			writeback = 1;
371987da915Sopenharmony_ci			if (NVolFreeSpaceKnown(vol)) {
372987da915Sopenharmony_ci				if (vol->free_clusters <= 0)
373987da915Sopenharmony_ci					ntfs_log_error("Non-positive free"
374987da915Sopenharmony_ci					       " clusters (%lld)!\n",
375987da915Sopenharmony_ci						(long long)vol->free_clusters);
376987da915Sopenharmony_ci				else
377987da915Sopenharmony_ci					vol->free_clusters--;
378987da915Sopenharmony_ci			}
379987da915Sopenharmony_ci
380987da915Sopenharmony_ci			/*
381987da915Sopenharmony_ci			 * Coalesce with previous run if adjacent LCNs.
382987da915Sopenharmony_ci			 * Otherwise, append a new run.
383987da915Sopenharmony_ci			 */
384987da915Sopenharmony_ci			if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
385987da915Sopenharmony_ci				ntfs_log_debug("Cluster coalesce: prev_lcn: "
386987da915Sopenharmony_ci					       "%lld  lcn: %lld  bmp_pos: %lld  "
387987da915Sopenharmony_ci					       "prev_run_len: %lld\n",
388987da915Sopenharmony_ci					       (long long)prev_lcn,
389987da915Sopenharmony_ci					       (long long)lcn, (long long)bmp_pos,
390987da915Sopenharmony_ci					       (long long)prev_run_len);
391987da915Sopenharmony_ci				rl[rlpos - 1].length = ++prev_run_len;
392987da915Sopenharmony_ci			} else {
393987da915Sopenharmony_ci				if (rlpos)
394987da915Sopenharmony_ci					rl[rlpos].vcn = rl[rlpos - 1].vcn +
395987da915Sopenharmony_ci							prev_run_len;
396987da915Sopenharmony_ci				else {
397987da915Sopenharmony_ci					rl[rlpos].vcn = start_vcn;
398987da915Sopenharmony_ci					ntfs_log_debug("Start_vcn: %lld\n",
399987da915Sopenharmony_ci						       (long long)start_vcn);
400987da915Sopenharmony_ci				}
401987da915Sopenharmony_ci
402987da915Sopenharmony_ci				rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
403987da915Sopenharmony_ci				rl[rlpos].length = prev_run_len = 1;
404987da915Sopenharmony_ci				rlpos++;
405987da915Sopenharmony_ci			}
406987da915Sopenharmony_ci
407987da915Sopenharmony_ci			ntfs_log_debug("RUN:   %-16lld %-16lld %-16lld\n",
408987da915Sopenharmony_ci				       (long long)rl[rlpos - 1].vcn,
409987da915Sopenharmony_ci				       (long long)rl[rlpos - 1].lcn,
410987da915Sopenharmony_ci				       (long long)rl[rlpos - 1].length);
411987da915Sopenharmony_ci			/* Done? */
412987da915Sopenharmony_ci			if (!--clusters) {
413987da915Sopenharmony_ci				if (used_zone_pos)
414987da915Sopenharmony_ci					ntfs_cluster_update_zone_pos(vol,
415987da915Sopenharmony_ci						search_zone, lcn + bmp_pos + 1 +
416987da915Sopenharmony_ci							NTFS_LCNALLOC_SKIP);
417987da915Sopenharmony_ci				goto done_ret;
418987da915Sopenharmony_ci			}
419987da915Sopenharmony_ci
420987da915Sopenharmony_ci			lcn++;
421987da915Sopenharmony_ci		}
422987da915Sopenharmony_ci
423987da915Sopenharmony_ci		if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
424987da915Sopenharmony_ci			err = errno;
425987da915Sopenharmony_ci			goto err_ret;
426987da915Sopenharmony_ci		}
427987da915Sopenharmony_ci
428987da915Sopenharmony_ci		if (!used_zone_pos) {
429987da915Sopenharmony_ci
430987da915Sopenharmony_ci			used_zone_pos = 1;
431987da915Sopenharmony_ci
432987da915Sopenharmony_ci			if (search_zone == ZONE_MFT)
433987da915Sopenharmony_ci				zone_start = vol->mft_zone_pos;
434987da915Sopenharmony_ci			else if (search_zone == ZONE_DATA1)
435987da915Sopenharmony_ci				zone_start = vol->data1_zone_pos;
436987da915Sopenharmony_ci			else
437987da915Sopenharmony_ci				zone_start = vol->data2_zone_pos;
438987da915Sopenharmony_ci
439987da915Sopenharmony_ci			if (!zone_start || zone_start == vol->mft_zone_start ||
440987da915Sopenharmony_ci					zone_start == vol->mft_zone_end)
441987da915Sopenharmony_ci				pass = 2;
442987da915Sopenharmony_ci			bmp_pos = zone_start;
443987da915Sopenharmony_ci		} else
444987da915Sopenharmony_ci			bmp_pos += buf_size;
445987da915Sopenharmony_ci
446987da915Sopenharmony_ci		if (bmp_pos < zone_end)
447987da915Sopenharmony_ci			continue;
448987da915Sopenharmony_ci
449987da915Sopenharmony_cizone_pass_done:
450987da915Sopenharmony_ci		ntfs_log_trace("Finished current zone pass(%i).\n", pass);
451987da915Sopenharmony_ci		if (pass == 1) {
452987da915Sopenharmony_ci			pass = 2;
453987da915Sopenharmony_ci			zone_end = zone_start;
454987da915Sopenharmony_ci
455987da915Sopenharmony_ci			if (search_zone == ZONE_MFT)
456987da915Sopenharmony_ci				zone_start = vol->mft_zone_start;
457987da915Sopenharmony_ci			else if (search_zone == ZONE_DATA1)
458987da915Sopenharmony_ci				zone_start = vol->mft_zone_end;
459987da915Sopenharmony_ci			else
460987da915Sopenharmony_ci				zone_start = 0;
461987da915Sopenharmony_ci
462987da915Sopenharmony_ci			/* Sanity check. */
463987da915Sopenharmony_ci			if (zone_end < zone_start)
464987da915Sopenharmony_ci				zone_end = zone_start;
465987da915Sopenharmony_ci
466987da915Sopenharmony_ci			bmp_pos = zone_start;
467987da915Sopenharmony_ci
468987da915Sopenharmony_ci			continue;
469987da915Sopenharmony_ci		}
470987da915Sopenharmony_ci		/* pass == 2 */
471987da915Sopenharmony_cidone_zones_check:
472987da915Sopenharmony_ci		done_zones |= search_zone;
473987da915Sopenharmony_ci		vol->full_zones |= search_zone;
474987da915Sopenharmony_ci		if (done_zones < (ZONE_MFT + ZONE_DATA1 + ZONE_DATA2)) {
475987da915Sopenharmony_ci			ntfs_log_trace("Switching zone.\n");
476987da915Sopenharmony_ci			pass = 1;
477987da915Sopenharmony_ci			if (rlpos) {
478987da915Sopenharmony_ci				LCN tc = rl[rlpos - 1].lcn +
479987da915Sopenharmony_ci				      rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
480987da915Sopenharmony_ci
481987da915Sopenharmony_ci				if (used_zone_pos)
482987da915Sopenharmony_ci					ntfs_cluster_update_zone_pos(vol,
483987da915Sopenharmony_ci						search_zone, tc);
484987da915Sopenharmony_ci			}
485987da915Sopenharmony_ci
486987da915Sopenharmony_ci			switch (search_zone) {
487987da915Sopenharmony_ci			case ZONE_MFT:
488987da915Sopenharmony_ci				ntfs_log_trace("Zone switch: mft -> data1\n");
489987da915Sopenharmony_ciswitch_to_data1_zone:		search_zone = ZONE_DATA1;
490987da915Sopenharmony_ci				zone_start = vol->data1_zone_pos;
491987da915Sopenharmony_ci				zone_end = vol->nr_clusters;
492987da915Sopenharmony_ci				if (zone_start == vol->mft_zone_end)
493987da915Sopenharmony_ci					pass = 2;
494987da915Sopenharmony_ci				break;
495987da915Sopenharmony_ci			case ZONE_DATA1:
496987da915Sopenharmony_ci				ntfs_log_trace("Zone switch: data1 -> data2\n");
497987da915Sopenharmony_ci				search_zone = ZONE_DATA2;
498987da915Sopenharmony_ci				zone_start = vol->data2_zone_pos;
499987da915Sopenharmony_ci				zone_end = vol->mft_zone_start;
500987da915Sopenharmony_ci				if (!zone_start)
501987da915Sopenharmony_ci					pass = 2;
502987da915Sopenharmony_ci				break;
503987da915Sopenharmony_ci			case ZONE_DATA2:
504987da915Sopenharmony_ci				if (!(done_zones & ZONE_DATA1)) {
505987da915Sopenharmony_ci					ntfs_log_trace("data2 -> data1\n");
506987da915Sopenharmony_ci					goto switch_to_data1_zone;
507987da915Sopenharmony_ci				}
508987da915Sopenharmony_ci				ntfs_log_trace("Zone switch: data2 -> mft\n");
509987da915Sopenharmony_ci				search_zone = ZONE_MFT;
510987da915Sopenharmony_ci				zone_start = vol->mft_zone_pos;
511987da915Sopenharmony_ci				zone_end = vol->mft_zone_end;
512987da915Sopenharmony_ci				if (zone_start == vol->mft_zone_start)
513987da915Sopenharmony_ci					pass = 2;
514987da915Sopenharmony_ci				break;
515987da915Sopenharmony_ci			}
516987da915Sopenharmony_ci
517987da915Sopenharmony_ci			bmp_pos = zone_start;
518987da915Sopenharmony_ci
519987da915Sopenharmony_ci			if (zone_start == zone_end) {
520987da915Sopenharmony_ci				ntfs_log_trace("Empty zone, skipped.\n");
521987da915Sopenharmony_ci				goto done_zones_check;
522987da915Sopenharmony_ci			}
523987da915Sopenharmony_ci
524987da915Sopenharmony_ci			continue;
525987da915Sopenharmony_ci		}
526987da915Sopenharmony_ci
527987da915Sopenharmony_ci		ntfs_log_trace("All zones are finished, no space on device.\n");
528987da915Sopenharmony_ci		err = ENOSPC;
529987da915Sopenharmony_ci		goto err_ret;
530987da915Sopenharmony_ci	}
531987da915Sopenharmony_cidone_ret:
532987da915Sopenharmony_ci	ntfs_log_debug("At done_ret.\n");
533987da915Sopenharmony_ci	/* Add runlist terminator element. */
534987da915Sopenharmony_ci	rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
535987da915Sopenharmony_ci	rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
536987da915Sopenharmony_ci	rl[rlpos].length = 0;
537987da915Sopenharmony_ci	if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
538987da915Sopenharmony_ci		err = errno;
539987da915Sopenharmony_ci		goto err_ret;
540987da915Sopenharmony_ci	}
541987da915Sopenharmony_cidone_err_ret:
542987da915Sopenharmony_ci	free(buf);
543987da915Sopenharmony_ci	if (err) {
544987da915Sopenharmony_ci		errno = err;
545987da915Sopenharmony_ci		ntfs_log_perror("Failed to allocate clusters");
546987da915Sopenharmony_ci		rl = NULL;
547987da915Sopenharmony_ci	}
548987da915Sopenharmony_ciout:
549987da915Sopenharmony_ci	ntfs_log_leave("\n");
550987da915Sopenharmony_ci	return rl;
551987da915Sopenharmony_ci
552987da915Sopenharmony_ciwb_err_ret:
553987da915Sopenharmony_ci	ntfs_log_trace("At wb_err_ret.\n");
554987da915Sopenharmony_ci	if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback))
555987da915Sopenharmony_ci		err = errno;
556987da915Sopenharmony_cierr_ret:
557987da915Sopenharmony_ci	ntfs_log_trace("At err_ret.\n");
558987da915Sopenharmony_ci	if (rl) {
559987da915Sopenharmony_ci		/* Add runlist terminator element. */
560987da915Sopenharmony_ci		rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
561987da915Sopenharmony_ci		rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
562987da915Sopenharmony_ci		rl[rlpos].length = 0;
563987da915Sopenharmony_ci		ntfs_debug_runlist_dump(rl);
564987da915Sopenharmony_ci		ntfs_cluster_free_from_rl(vol, rl);
565987da915Sopenharmony_ci		free(rl);
566987da915Sopenharmony_ci		rl = NULL;
567987da915Sopenharmony_ci	}
568987da915Sopenharmony_ci	goto done_err_ret;
569987da915Sopenharmony_ci}
570987da915Sopenharmony_ci
571987da915Sopenharmony_ci/**
572987da915Sopenharmony_ci * ntfs_cluster_free_from_rl - free clusters from runlist
573987da915Sopenharmony_ci * @vol:	mounted ntfs volume on which to free the clusters
574987da915Sopenharmony_ci * @rl:		runlist from which deallocate clusters
575987da915Sopenharmony_ci *
576987da915Sopenharmony_ci * On success return 0 and on error return -1 with errno set to the error code.
577987da915Sopenharmony_ci */
578987da915Sopenharmony_ciint ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
579987da915Sopenharmony_ci{
580987da915Sopenharmony_ci	s64 nr_freed = 0;
581987da915Sopenharmony_ci	int ret = -1;
582987da915Sopenharmony_ci
583987da915Sopenharmony_ci	ntfs_log_trace("Entering.\n");
584987da915Sopenharmony_ci
585987da915Sopenharmony_ci	for (; rl->length; rl++) {
586987da915Sopenharmony_ci
587987da915Sopenharmony_ci		ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
588987da915Sopenharmony_ci			       (long long)rl->lcn, (long long)rl->length);
589987da915Sopenharmony_ci
590987da915Sopenharmony_ci		if (rl->lcn >= 0) {
591987da915Sopenharmony_ci			update_full_status(vol,rl->lcn);
592987da915Sopenharmony_ci			if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
593987da915Sopenharmony_ci						  rl->length)) {
594987da915Sopenharmony_ci				ntfs_log_perror("Cluster deallocation failed "
595987da915Sopenharmony_ci					       "(%lld, %lld)",
596987da915Sopenharmony_ci						(long long)rl->lcn,
597987da915Sopenharmony_ci						(long long)rl->length);
598987da915Sopenharmony_ci				goto out;
599987da915Sopenharmony_ci			}
600987da915Sopenharmony_ci			nr_freed += rl->length ;
601987da915Sopenharmony_ci		}
602987da915Sopenharmony_ci	}
603987da915Sopenharmony_ci
604987da915Sopenharmony_ci	ret = 0;
605987da915Sopenharmony_ciout:
606987da915Sopenharmony_ci	vol->free_clusters += nr_freed;
607987da915Sopenharmony_ci	if (NVolFreeSpaceKnown(vol)
608987da915Sopenharmony_ci	    && (vol->free_clusters > vol->nr_clusters))
609987da915Sopenharmony_ci		ntfs_log_error("Too many free clusters (%lld > %lld)!",
610987da915Sopenharmony_ci			       (long long)vol->free_clusters,
611987da915Sopenharmony_ci			       (long long)vol->nr_clusters);
612987da915Sopenharmony_ci	return ret;
613987da915Sopenharmony_ci}
614987da915Sopenharmony_ci
615987da915Sopenharmony_ci/*
616987da915Sopenharmony_ci *		Basic cluster run free
617987da915Sopenharmony_ci *	Returns 0 if successful
618987da915Sopenharmony_ci */
619987da915Sopenharmony_ci
620987da915Sopenharmony_ciint ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count)
621987da915Sopenharmony_ci{
622987da915Sopenharmony_ci	s64 nr_freed = 0;
623987da915Sopenharmony_ci	int ret = -1;
624987da915Sopenharmony_ci
625987da915Sopenharmony_ci	ntfs_log_trace("Entering.\n");
626987da915Sopenharmony_ci	ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
627987da915Sopenharmony_ci			       (long long)lcn, (long long)count);
628987da915Sopenharmony_ci
629987da915Sopenharmony_ci	if (lcn >= 0) {
630987da915Sopenharmony_ci		update_full_status(vol,lcn);
631987da915Sopenharmony_ci		if (ntfs_bitmap_clear_run(vol->lcnbmp_na, lcn,
632987da915Sopenharmony_ci						  count)) {
633987da915Sopenharmony_ci			ntfs_log_perror("Cluster deallocation failed "
634987da915Sopenharmony_ci				       "(%lld, %lld)",
635987da915Sopenharmony_ci					(long long)lcn,
636987da915Sopenharmony_ci					(long long)count);
637987da915Sopenharmony_ci				goto out;
638987da915Sopenharmony_ci		}
639987da915Sopenharmony_ci		nr_freed += count;
640987da915Sopenharmony_ci	}
641987da915Sopenharmony_ci	ret = 0;
642987da915Sopenharmony_ciout:
643987da915Sopenharmony_ci	vol->free_clusters += nr_freed;
644987da915Sopenharmony_ci	if (vol->free_clusters > vol->nr_clusters)
645987da915Sopenharmony_ci		ntfs_log_error("Too many free clusters (%lld > %lld)!",
646987da915Sopenharmony_ci			       (long long)vol->free_clusters,
647987da915Sopenharmony_ci			       (long long)vol->nr_clusters);
648987da915Sopenharmony_ci	return ret;
649987da915Sopenharmony_ci}
650987da915Sopenharmony_ci
651987da915Sopenharmony_ci/**
652987da915Sopenharmony_ci * ntfs_cluster_free - free clusters on an ntfs volume
653987da915Sopenharmony_ci * @vol:	mounted ntfs volume on which to free the clusters
654987da915Sopenharmony_ci * @na:		attribute whose runlist describes the clusters to free
655987da915Sopenharmony_ci * @start_vcn:	vcn in @rl at which to start freeing clusters
656987da915Sopenharmony_ci * @count:	number of clusters to free or -1 for all clusters
657987da915Sopenharmony_ci *
658987da915Sopenharmony_ci * Free @count clusters starting at the cluster @start_vcn in the runlist
659987da915Sopenharmony_ci * described by the attribute @na from the mounted ntfs volume @vol.
660987da915Sopenharmony_ci *
661987da915Sopenharmony_ci * If @count is -1, all clusters from @start_vcn to the end of the runlist
662987da915Sopenharmony_ci * are deallocated.
663987da915Sopenharmony_ci *
664987da915Sopenharmony_ci * On success return the number of deallocated clusters (not counting sparse
665987da915Sopenharmony_ci * clusters) and on error return -1 with errno set to the error code.
666987da915Sopenharmony_ci */
667987da915Sopenharmony_ciint ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
668987da915Sopenharmony_ci{
669987da915Sopenharmony_ci	runlist *rl;
670987da915Sopenharmony_ci	s64 delta, to_free, nr_freed = 0;
671987da915Sopenharmony_ci	int ret = -1;
672987da915Sopenharmony_ci
673987da915Sopenharmony_ci	if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
674987da915Sopenharmony_ci			(count < 0 && count != -1)) {
675987da915Sopenharmony_ci		ntfs_log_trace("Invalid arguments!\n");
676987da915Sopenharmony_ci		errno = EINVAL;
677987da915Sopenharmony_ci		return -1;
678987da915Sopenharmony_ci	}
679987da915Sopenharmony_ci
680987da915Sopenharmony_ci	ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
681987da915Sopenharmony_ci		       "vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no,
682987da915Sopenharmony_ci		       le32_to_cpu(na->type), (long long)count, (long long)start_vcn);
683987da915Sopenharmony_ci
684987da915Sopenharmony_ci	rl = ntfs_attr_find_vcn(na, start_vcn);
685987da915Sopenharmony_ci	if (!rl) {
686987da915Sopenharmony_ci		if (errno == ENOENT)
687987da915Sopenharmony_ci			ret = 0;
688987da915Sopenharmony_ci		goto leave;
689987da915Sopenharmony_ci	}
690987da915Sopenharmony_ci
691987da915Sopenharmony_ci	if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
692987da915Sopenharmony_ci		errno = EIO;
693987da915Sopenharmony_ci		ntfs_log_perror("%s: Unexpected lcn (%lld)", __FUNCTION__,
694987da915Sopenharmony_ci				(long long)rl->lcn);
695987da915Sopenharmony_ci		goto leave;
696987da915Sopenharmony_ci	}
697987da915Sopenharmony_ci
698987da915Sopenharmony_ci	/* Find the starting cluster inside the run that needs freeing. */
699987da915Sopenharmony_ci	delta = start_vcn - rl->vcn;
700987da915Sopenharmony_ci
701987da915Sopenharmony_ci	/* The number of clusters in this run that need freeing. */
702987da915Sopenharmony_ci	to_free = rl->length - delta;
703987da915Sopenharmony_ci	if (count >= 0 && to_free > count)
704987da915Sopenharmony_ci		to_free = count;
705987da915Sopenharmony_ci
706987da915Sopenharmony_ci	if (rl->lcn != LCN_HOLE) {
707987da915Sopenharmony_ci		/* Do the actual freeing of the clusters in this run. */
708987da915Sopenharmony_ci		update_full_status(vol,rl->lcn + delta);
709987da915Sopenharmony_ci		if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta,
710987da915Sopenharmony_ci					  to_free))
711987da915Sopenharmony_ci			goto leave;
712987da915Sopenharmony_ci		nr_freed = to_free;
713987da915Sopenharmony_ci	}
714987da915Sopenharmony_ci
715987da915Sopenharmony_ci	/* Go to the next run and adjust the number of clusters left to free. */
716987da915Sopenharmony_ci	++rl;
717987da915Sopenharmony_ci	if (count >= 0)
718987da915Sopenharmony_ci		count -= to_free;
719987da915Sopenharmony_ci
720987da915Sopenharmony_ci	/*
721987da915Sopenharmony_ci	 * Loop over the remaining runs, using @count as a capping value, and
722987da915Sopenharmony_ci	 * free them.
723987da915Sopenharmony_ci	 */
724987da915Sopenharmony_ci	for (; rl->length && count != 0; ++rl) {
725987da915Sopenharmony_ci		// FIXME: Need to try ntfs_attr_map_runlist() for attribute
726987da915Sopenharmony_ci		//	  list support! (AIA)
727987da915Sopenharmony_ci		if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
728987da915Sopenharmony_ci			// FIXME: Eeek! We need rollback! (AIA)
729987da915Sopenharmony_ci			errno = EIO;
730987da915Sopenharmony_ci			ntfs_log_perror("%s: Invalid lcn (%lli)",
731987da915Sopenharmony_ci					__FUNCTION__, (long long)rl->lcn);
732987da915Sopenharmony_ci			goto out;
733987da915Sopenharmony_ci		}
734987da915Sopenharmony_ci
735987da915Sopenharmony_ci		/* The number of clusters in this run that need freeing. */
736987da915Sopenharmony_ci		to_free = rl->length;
737987da915Sopenharmony_ci		if (count >= 0 && to_free > count)
738987da915Sopenharmony_ci			to_free = count;
739987da915Sopenharmony_ci
740987da915Sopenharmony_ci		if (rl->lcn != LCN_HOLE) {
741987da915Sopenharmony_ci			update_full_status(vol,rl->lcn);
742987da915Sopenharmony_ci			if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
743987da915Sopenharmony_ci					to_free)) {
744987da915Sopenharmony_ci				// FIXME: Eeek! We need rollback! (AIA)
745987da915Sopenharmony_ci				ntfs_log_perror("%s: Clearing bitmap run failed",
746987da915Sopenharmony_ci						__FUNCTION__);
747987da915Sopenharmony_ci				goto out;
748987da915Sopenharmony_ci			}
749987da915Sopenharmony_ci			nr_freed += to_free;
750987da915Sopenharmony_ci		}
751987da915Sopenharmony_ci
752987da915Sopenharmony_ci		if (count >= 0)
753987da915Sopenharmony_ci			count -= to_free;
754987da915Sopenharmony_ci	}
755987da915Sopenharmony_ci
756987da915Sopenharmony_ci	if (count != -1 && count != 0) {
757987da915Sopenharmony_ci		// FIXME: Eeek! BUG()
758987da915Sopenharmony_ci		errno = EIO;
759987da915Sopenharmony_ci		ntfs_log_perror("%s: count still not zero (%lld)", __FUNCTION__,
760987da915Sopenharmony_ci			       (long long)count);
761987da915Sopenharmony_ci		goto out;
762987da915Sopenharmony_ci	}
763987da915Sopenharmony_ci
764987da915Sopenharmony_ci	ret = nr_freed;
765987da915Sopenharmony_ciout:
766987da915Sopenharmony_ci	vol->free_clusters += nr_freed ;
767987da915Sopenharmony_ci	if (vol->free_clusters > vol->nr_clusters)
768987da915Sopenharmony_ci		ntfs_log_error("Too many free clusters (%lld > %lld)!",
769987da915Sopenharmony_ci			       (long long)vol->free_clusters,
770987da915Sopenharmony_ci			       (long long)vol->nr_clusters);
771987da915Sopenharmony_cileave:
772987da915Sopenharmony_ci	ntfs_log_leave("\n");
773987da915Sopenharmony_ci	return ret;
774987da915Sopenharmony_ci}
775