1564 lines · 32.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. * * This code builds two trees of free clusters extents. * Trees are sorted by start of extent and by length of extent. * NTFS_MAX_WND_EXTENTS defines the maximum number of elements in trees. * In extreme case code reads on-disk bitmap to find free clusters. * */ #include <linux/buffer_head.h>#include <linux/fs.h>#include <linux/kernel.h> #include "ntfs.h"#include "ntfs_fs.h" /* * Maximum number of extents in tree. */#define NTFS_MAX_WND_EXTENTS (32u * 1024u) struct rb_node_key {	struct rb_node node;	size_t key;}; struct e_node {	struct rb_node_key start; /* Tree sorted by start. */	struct rb_node_key count; /* Tree sorted by len. */}; static int wnd_rescan(struct wnd_bitmap *wnd);static struct buffer_head *wnd_map(struct wnd_bitmap *wnd, size_t iw);static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits); static struct kmem_cache *ntfs_enode_cachep; int __init ntfs3_init_bitmap(void){	ntfs_enode_cachep = kmem_cache_create("ntfs3_enode_cache",					      sizeof(struct e_node), 0,					      SLAB_RECLAIM_ACCOUNT, NULL);	return ntfs_enode_cachep ? 0 : -ENOMEM;} void ntfs3_exit_bitmap(void){	kmem_cache_destroy(ntfs_enode_cachep);} /* * wnd_scan * * b_pos + b_len - biggest fragment. * Scan range [wpos wbits) window @buf. * * Return: -1 if not found. */static size_t wnd_scan(const void *buf, size_t wbit, u32 wpos, u32 wend,		       size_t to_alloc, size_t *prev_tail, size_t *b_pos,		       size_t *b_len){	while (wpos < wend) {		size_t free_len;		u32 free_bits, end;		u32 used = find_next_zero_bit_le(buf, wend, wpos); 		if (used >= wend) {			if (*b_len < *prev_tail) {				*b_pos = wbit - *prev_tail;				*b_len = *prev_tail;			} 			*prev_tail = 0;			return -1;		} 		if (used > wpos) {			wpos = used;			if (*b_len < *prev_tail) {				*b_pos = wbit - *prev_tail;				*b_len = *prev_tail;			} 			*prev_tail = 0;		} 		/*		 * Now we have a fragment [wpos, wend) staring with 0.		 */		end = wpos + to_alloc - *prev_tail;		free_bits = find_next_bit_le(buf, min(end, wend), wpos); 		free_len = *prev_tail + free_bits - wpos; 		if (*b_len < free_len) {			*b_pos = wbit + wpos - *prev_tail;			*b_len = free_len;		} 		if (free_len >= to_alloc)			return wbit + wpos - *prev_tail; 		if (free_bits >= wend) {			*prev_tail += free_bits - wpos;			return -1;		} 		wpos = free_bits + 1; 		*prev_tail = 0;	} 	return -1;} /* * wnd_close - Frees all resources. */void wnd_close(struct wnd_bitmap *wnd){	struct rb_node *node, *next; 	kvfree(wnd->free_bits);	wnd->free_bits = NULL;	run_close(&wnd->run); 	node = rb_first(&wnd->start_tree); 	while (node) {		next = rb_next(node);		rb_erase(node, &wnd->start_tree);		kmem_cache_free(ntfs_enode_cachep,				rb_entry(node, struct e_node, start.node));		node = next;	}} static struct rb_node *rb_lookup(struct rb_root *root, size_t v){	struct rb_node **p = &root->rb_node;	struct rb_node *r = NULL; 	while (*p) {		struct rb_node_key *k; 		k = rb_entry(*p, struct rb_node_key, node);		if (v < k->key) {			p = &(*p)->rb_left;		} else if (v > k->key) {			r = &k->node;			p = &(*p)->rb_right;		} else {			return &k->node;		}	} 	return r;} /* * rb_insert_count - Helper function to insert special kind of 'count' tree. */static inline bool rb_insert_count(struct rb_root *root, struct e_node *e){	struct rb_node **p = &root->rb_node;	struct rb_node *parent = NULL;	size_t e_ckey = e->count.key;	size_t e_skey = e->start.key; 	while (*p) {		struct e_node *k =			rb_entry(parent = *p, struct e_node, count.node); 		if (e_ckey > k->count.key) {			p = &(*p)->rb_left;		} else if (e_ckey < k->count.key) {			p = &(*p)->rb_right;		} else if (e_skey < k->start.key) {			p = &(*p)->rb_left;		} else if (e_skey > k->start.key) {			p = &(*p)->rb_right;		} else {			WARN_ON(1);			return false;		}	} 	rb_link_node(&e->count.node, parent, p);	rb_insert_color(&e->count.node, root);	return true;} /* * rb_insert_start - Helper function to insert special kind of 'count' tree. */static inline bool rb_insert_start(struct rb_root *root, struct e_node *e){	struct rb_node **p = &root->rb_node;	struct rb_node *parent = NULL;	size_t e_skey = e->start.key; 	while (*p) {		struct e_node *k; 		parent = *p; 		k = rb_entry(parent, struct e_node, start.node);		if (e_skey < k->start.key) {			p = &(*p)->rb_left;		} else if (e_skey > k->start.key) {			p = &(*p)->rb_right;		} else {			WARN_ON(1);			return false;		}	} 	rb_link_node(&e->start.node, parent, p);	rb_insert_color(&e->start.node, root);	return true;} /* * wnd_add_free_ext - Adds a new extent of free space. * @build:	1 when building tree. */static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len,			     bool build){	struct e_node *e, *e0 = NULL;	size_t ib, end_in = bit + len;	struct rb_node *n; 	if (build) {		/* Use extent_min to filter too short extents. */		if (wnd->count >= NTFS_MAX_WND_EXTENTS &&		    len <= wnd->extent_min) {			wnd->uptodated = -1;			return;		}	} else {		/* Try to find extent before 'bit'. */		n = rb_lookup(&wnd->start_tree, bit); 		if (!n) {			n = rb_first(&wnd->start_tree);		} else {			e = rb_entry(n, struct e_node, start.node);			n = rb_next(n);			if (e->start.key + e->count.key == bit) {				/* Remove left. */				bit = e->start.key;				len += e->count.key;				rb_erase(&e->start.node, &wnd->start_tree);				rb_erase(&e->count.node, &wnd->count_tree);				wnd->count -= 1;				e0 = e;			}		} 		while (n) {			size_t next_end; 			e = rb_entry(n, struct e_node, start.node);			next_end = e->start.key + e->count.key;			if (e->start.key > end_in)				break; 			/* Remove right. */			n = rb_next(n);			len += next_end - end_in;			end_in = next_end;			rb_erase(&e->start.node, &wnd->start_tree);			rb_erase(&e->count.node, &wnd->count_tree);			wnd->count -= 1; 			if (!e0)				e0 = e;			else				kmem_cache_free(ntfs_enode_cachep, e);		} 		if (wnd->uptodated != 1) {			/* Check bits before 'bit'. */			ib = wnd->zone_bit == wnd->zone_end ||					     bit < wnd->zone_end ?				     0 :				     wnd->zone_end; 			while (bit > ib && wnd_is_free_hlp(wnd, bit - 1, 1)) {				bit -= 1;				len += 1;			} 			/* Check bits after 'end_in'. */			ib = wnd->zone_bit == wnd->zone_end ||					     end_in > wnd->zone_bit ?				     wnd->nbits :				     wnd->zone_bit; 			while (end_in < ib && wnd_is_free_hlp(wnd, end_in, 1)) {				end_in += 1;				len += 1;			}		}	}	/* Insert new fragment. */	if (wnd->count >= NTFS_MAX_WND_EXTENTS) {		if (e0)			kmem_cache_free(ntfs_enode_cachep, e0); 		wnd->uptodated = -1; 		/* Compare with smallest fragment. */		n = rb_last(&wnd->count_tree);		e = rb_entry(n, struct e_node, count.node);		if (len <= e->count.key)			goto out; /* Do not insert small fragments. */ 		if (build) {			struct e_node *e2; 			n = rb_prev(n);			e2 = rb_entry(n, struct e_node, count.node);			/* Smallest fragment will be 'e2->count.key'. */			wnd->extent_min = e2->count.key;		} 		/* Replace smallest fragment by new one. */		rb_erase(&e->start.node, &wnd->start_tree);		rb_erase(&e->count.node, &wnd->count_tree);		wnd->count -= 1;	} else {		e = e0 ? e0 : kmem_cache_alloc(ntfs_enode_cachep, GFP_ATOMIC);		if (!e) {			wnd->uptodated = -1;			goto out;		} 		if (build && len <= wnd->extent_min)			wnd->extent_min = len;	}	e->start.key = bit;	e->count.key = len;	if (len > wnd->extent_max)		wnd->extent_max = len; 	rb_insert_start(&wnd->start_tree, e);	rb_insert_count(&wnd->count_tree, e);	wnd->count += 1; out:;} /* * wnd_remove_free_ext - Remove a run from the cached free space. */static void wnd_remove_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len){	struct rb_node *n, *n3;	struct e_node *e, *e3;	size_t end_in = bit + len;	size_t end3, end, new_key, new_len, max_new_len; 	/* Try to find extent before 'bit'. */	n = rb_lookup(&wnd->start_tree, bit); 	if (!n)		return; 	e = rb_entry(n, struct e_node, start.node);	end = e->start.key + e->count.key; 	new_key = new_len = 0;	len = e->count.key; 	/* Range [bit,end_in) must be inside 'e' or outside 'e' and 'n'. */	if (e->start.key > bit)		;	else if (end_in <= end) {		/* Range [bit,end_in) inside 'e'. */		new_key = end_in;		new_len = end - end_in;		len = bit - e->start.key;	} else if (bit > end) {		bool bmax = false; 		n3 = rb_next(n); 		while (n3) {			e3 = rb_entry(n3, struct e_node, start.node);			if (e3->start.key >= end_in)				break; 			if (e3->count.key == wnd->extent_max)				bmax = true; 			end3 = e3->start.key + e3->count.key;			if (end3 > end_in) {				e3->start.key = end_in;				rb_erase(&e3->count.node, &wnd->count_tree);				e3->count.key = end3 - end_in;				rb_insert_count(&wnd->count_tree, e3);				break;			} 			n3 = rb_next(n3);			rb_erase(&e3->start.node, &wnd->start_tree);			rb_erase(&e3->count.node, &wnd->count_tree);			wnd->count -= 1;			kmem_cache_free(ntfs_enode_cachep, e3);		}		if (!bmax)			return;		n3 = rb_first(&wnd->count_tree);		wnd->extent_max =			n3 ? rb_entry(n3, struct e_node, count.node)->count.key :			     0;		return;	} 	if (e->count.key != wnd->extent_max) {		;	} else if (rb_prev(&e->count.node)) {		;	} else {		n3 = rb_next(&e->count.node);		max_new_len = max(len, new_len);		if (!n3) {			wnd->extent_max = max_new_len;		} else {			e3 = rb_entry(n3, struct e_node, count.node);			wnd->extent_max = max(e3->count.key, max_new_len);		}	} 	if (!len) {		if (new_len) {			e->start.key = new_key;			rb_erase(&e->count.node, &wnd->count_tree);			e->count.key = new_len;			rb_insert_count(&wnd->count_tree, e);		} else {			rb_erase(&e->start.node, &wnd->start_tree);			rb_erase(&e->count.node, &wnd->count_tree);			wnd->count -= 1;			kmem_cache_free(ntfs_enode_cachep, e);		}		goto out;	}	rb_erase(&e->count.node, &wnd->count_tree);	e->count.key = len;	rb_insert_count(&wnd->count_tree, e); 	if (!new_len)		goto out; 	if (wnd->count >= NTFS_MAX_WND_EXTENTS) {		wnd->uptodated = -1; 		/* Get minimal extent. */		e = rb_entry(rb_last(&wnd->count_tree), struct e_node,			     count.node);		if (e->count.key > new_len)			goto out; 		/* Replace minimum. */		rb_erase(&e->start.node, &wnd->start_tree);		rb_erase(&e->count.node, &wnd->count_tree);		wnd->count -= 1;	} else {		e = kmem_cache_alloc(ntfs_enode_cachep, GFP_ATOMIC);		if (!e)			wnd->uptodated = -1;	} 	if (e) {		e->start.key = new_key;		e->count.key = new_len;		rb_insert_start(&wnd->start_tree, e);		rb_insert_count(&wnd->count_tree, e);		wnd->count += 1;	} out:	if (!wnd->count && 1 != wnd->uptodated)		wnd_rescan(wnd);} /* * wnd_rescan - Scan all bitmap. Used while initialization. */static int wnd_rescan(struct wnd_bitmap *wnd){	int err = 0;	size_t prev_tail = 0;

Lines 1–500 of 1564.