xref: /openbmc/linux/fs/ntfs/attrib.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1a1d312deSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
27e0af978SYang Li /*
31da177e4SLinus Torvalds  * attrib.c - NTFS attribute operations.  Part of the Linux-NTFS project.
41da177e4SLinus Torvalds  *
545d95bcdSAnton Altaparmakov  * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc.
61da177e4SLinus Torvalds  * Copyright (c) 2002 Richard Russon
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/buffer_head.h>
1029b89905SAnton Altaparmakov #include <linux/sched.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
121ef334d3SAnton Altaparmakov #include <linux/swap.h>
1329b89905SAnton Altaparmakov #include <linux/writeback.h>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include "attrib.h"
161da177e4SLinus Torvalds #include "debug.h"
171da177e4SLinus Torvalds #include "layout.h"
182bfb4fffSAnton Altaparmakov #include "lcnalloc.h"
192bfb4fffSAnton Altaparmakov #include "malloc.h"
201da177e4SLinus Torvalds #include "mft.h"
211da177e4SLinus Torvalds #include "ntfs.h"
221da177e4SLinus Torvalds #include "types.h"
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds /**
25b6ad6c52SAnton Altaparmakov  * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode
261da177e4SLinus Torvalds  * @ni:		ntfs inode for which to map (part of) a runlist
271da177e4SLinus Torvalds  * @vcn:	map runlist part containing this vcn
28fd9d6367SAnton Altaparmakov  * @ctx:	active attribute search context if present or NULL if not
291da177e4SLinus Torvalds  *
301da177e4SLinus Torvalds  * Map the part of a runlist containing the @vcn of the ntfs inode @ni.
311da177e4SLinus Torvalds  *
32fd9d6367SAnton Altaparmakov  * If @ctx is specified, it is an active search context of @ni and its base mft
33fd9d6367SAnton Altaparmakov  * record.  This is needed when ntfs_map_runlist_nolock() encounters unmapped
34fd9d6367SAnton Altaparmakov  * runlist fragments and allows their mapping.  If you do not have the mft
35fd9d6367SAnton Altaparmakov  * record mapped, you can specify @ctx as NULL and ntfs_map_runlist_nolock()
36fd9d6367SAnton Altaparmakov  * will perform the necessary mapping and unmapping.
37fd9d6367SAnton Altaparmakov  *
38fd9d6367SAnton Altaparmakov  * Note, ntfs_map_runlist_nolock() saves the state of @ctx on entry and
39fd9d6367SAnton Altaparmakov  * restores it before returning.  Thus, @ctx will be left pointing to the same
40fd9d6367SAnton Altaparmakov  * attribute on return as on entry.  However, the actual pointers in @ctx may
41fd9d6367SAnton Altaparmakov  * point to different memory locations on return, so you must remember to reset
42fd9d6367SAnton Altaparmakov  * any cached pointers from the @ctx, i.e. after the call to
43fd9d6367SAnton Altaparmakov  * ntfs_map_runlist_nolock(), you will probably want to do:
44fd9d6367SAnton Altaparmakov  *	m = ctx->mrec;
45fd9d6367SAnton Altaparmakov  *	a = ctx->attr;
46fd9d6367SAnton Altaparmakov  * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
47fd9d6367SAnton Altaparmakov  * you cache ctx->mrec in a variable @m of type MFT_RECORD *.
48fd9d6367SAnton Altaparmakov  *
494757d7dfSAnton Altaparmakov  * Return 0 on success and -errno on error.  There is one special error code
504757d7dfSAnton Altaparmakov  * which is not an error as such.  This is -ENOENT.  It means that @vcn is out
514757d7dfSAnton Altaparmakov  * of bounds of the runlist.
521da177e4SLinus Torvalds  *
532983d1bdSAnton Altaparmakov  * Note the runlist can be NULL after this function returns if @vcn is zero and
542983d1bdSAnton Altaparmakov  * the attribute has zero allocated size, i.e. there simply is no runlist.
552983d1bdSAnton Altaparmakov  *
56fd9d6367SAnton Altaparmakov  * WARNING: If @ctx is supplied, regardless of whether success or failure is
57c49c3111SRichard Knutsson  *	    returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
58fd9d6367SAnton Altaparmakov  *	    is no longer valid, i.e. you need to either call
59fd9d6367SAnton Altaparmakov  *	    ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
60fd9d6367SAnton Altaparmakov  *	    In that case PTR_ERR(@ctx->mrec) will give you the error code for
61fd9d6367SAnton Altaparmakov  *	    why the mapping of the old inode failed.
62fd9d6367SAnton Altaparmakov  *
63fd9d6367SAnton Altaparmakov  * Locking: - The runlist described by @ni must be locked for writing on entry
64fd9d6367SAnton Altaparmakov  *	      and is locked on return.  Note the runlist will be modified.
65fd9d6367SAnton Altaparmakov  *	    - If @ctx is NULL, the base mft record of @ni must not be mapped on
66fd9d6367SAnton Altaparmakov  *	      entry and it will be left unmapped on return.
67fd9d6367SAnton Altaparmakov  *	    - If @ctx is not NULL, the base mft record must be mapped on entry
68fd9d6367SAnton Altaparmakov  *	      and it will be left mapped on return.
691da177e4SLinus Torvalds  */
ntfs_map_runlist_nolock(ntfs_inode * ni,VCN vcn,ntfs_attr_search_ctx * ctx)70fd9d6367SAnton Altaparmakov int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx)
711da177e4SLinus Torvalds {
724757d7dfSAnton Altaparmakov 	VCN end_vcn;
73fd9d6367SAnton Altaparmakov 	unsigned long flags;
741da177e4SLinus Torvalds 	ntfs_inode *base_ni;
754757d7dfSAnton Altaparmakov 	MFT_RECORD *m;
764757d7dfSAnton Altaparmakov 	ATTR_RECORD *a;
77b6ad6c52SAnton Altaparmakov 	runlist_element *rl;
78fd9d6367SAnton Altaparmakov 	struct page *put_this_page = NULL;
791da177e4SLinus Torvalds 	int err = 0;
80c49c3111SRichard Knutsson 	bool ctx_is_temporary, ctx_needs_reset;
81dda65b94SAnton Altaparmakov 	ntfs_attr_search_ctx old_ctx = { NULL, };
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds 	ntfs_debug("Mapping runlist part containing vcn 0x%llx.",
841da177e4SLinus Torvalds 			(unsigned long long)vcn);
851da177e4SLinus Torvalds 	if (!NInoAttr(ni))
861da177e4SLinus Torvalds 		base_ni = ni;
871da177e4SLinus Torvalds 	else
881da177e4SLinus Torvalds 		base_ni = ni->ext.base_ntfs_ino;
89fd9d6367SAnton Altaparmakov 	if (!ctx) {
90c49c3111SRichard Knutsson 		ctx_is_temporary = ctx_needs_reset = true;
914757d7dfSAnton Altaparmakov 		m = map_mft_record(base_ni);
924757d7dfSAnton Altaparmakov 		if (IS_ERR(m))
934757d7dfSAnton Altaparmakov 			return PTR_ERR(m);
944757d7dfSAnton Altaparmakov 		ctx = ntfs_attr_get_search_ctx(base_ni, m);
951da177e4SLinus Torvalds 		if (unlikely(!ctx)) {
961da177e4SLinus Torvalds 			err = -ENOMEM;
971da177e4SLinus Torvalds 			goto err_out;
981da177e4SLinus Torvalds 		}
99fd9d6367SAnton Altaparmakov 	} else {
100fd9d6367SAnton Altaparmakov 		VCN allocated_size_vcn;
101fd9d6367SAnton Altaparmakov 
102fd9d6367SAnton Altaparmakov 		BUG_ON(IS_ERR(ctx->mrec));
103fd9d6367SAnton Altaparmakov 		a = ctx->attr;
104fd9d6367SAnton Altaparmakov 		BUG_ON(!a->non_resident);
105c49c3111SRichard Knutsson 		ctx_is_temporary = false;
106fd9d6367SAnton Altaparmakov 		end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn);
107fd9d6367SAnton Altaparmakov 		read_lock_irqsave(&ni->size_lock, flags);
108fd9d6367SAnton Altaparmakov 		allocated_size_vcn = ni->allocated_size >>
109fd9d6367SAnton Altaparmakov 				ni->vol->cluster_size_bits;
110fd9d6367SAnton Altaparmakov 		read_unlock_irqrestore(&ni->size_lock, flags);
111fd9d6367SAnton Altaparmakov 		if (!a->data.non_resident.lowest_vcn && end_vcn <= 0)
112fd9d6367SAnton Altaparmakov 			end_vcn = allocated_size_vcn - 1;
113fd9d6367SAnton Altaparmakov 		/*
114fd9d6367SAnton Altaparmakov 		 * If we already have the attribute extent containing @vcn in
115fd9d6367SAnton Altaparmakov 		 * @ctx, no need to look it up again.  We slightly cheat in
116fd9d6367SAnton Altaparmakov 		 * that if vcn exceeds the allocated size, we will refuse to
117fd9d6367SAnton Altaparmakov 		 * map the runlist below, so there is definitely no need to get
118fd9d6367SAnton Altaparmakov 		 * the right attribute extent.
119fd9d6367SAnton Altaparmakov 		 */
120fd9d6367SAnton Altaparmakov 		if (vcn >= allocated_size_vcn || (a->type == ni->type &&
121fd9d6367SAnton Altaparmakov 				a->name_length == ni->name_len &&
122fd9d6367SAnton Altaparmakov 				!memcmp((u8*)a + le16_to_cpu(a->name_offset),
123fd9d6367SAnton Altaparmakov 				ni->name, ni->name_len) &&
124fd9d6367SAnton Altaparmakov 				sle64_to_cpu(a->data.non_resident.lowest_vcn)
125fd9d6367SAnton Altaparmakov 				<= vcn && end_vcn >= vcn))
126c49c3111SRichard Knutsson 			ctx_needs_reset = false;
127fd9d6367SAnton Altaparmakov 		else {
128fd9d6367SAnton Altaparmakov 			/* Save the old search context. */
129fd9d6367SAnton Altaparmakov 			old_ctx = *ctx;
130fd9d6367SAnton Altaparmakov 			/*
131fd9d6367SAnton Altaparmakov 			 * If the currently mapped (extent) inode is not the
132fd9d6367SAnton Altaparmakov 			 * base inode we will unmap it when we reinitialize the
133fd9d6367SAnton Altaparmakov 			 * search context which means we need to get a
134fd9d6367SAnton Altaparmakov 			 * reference to the page containing the mapped mft
135fd9d6367SAnton Altaparmakov 			 * record so we do not accidentally drop changes to the
136fd9d6367SAnton Altaparmakov 			 * mft record when it has not been marked dirty yet.
137fd9d6367SAnton Altaparmakov 			 */
138fd9d6367SAnton Altaparmakov 			if (old_ctx.base_ntfs_ino && old_ctx.ntfs_ino !=
139fd9d6367SAnton Altaparmakov 					old_ctx.base_ntfs_ino) {
140fd9d6367SAnton Altaparmakov 				put_this_page = old_ctx.ntfs_ino->page;
14109cbfeafSKirill A. Shutemov 				get_page(put_this_page);
142fd9d6367SAnton Altaparmakov 			}
143fd9d6367SAnton Altaparmakov 			/*
144fd9d6367SAnton Altaparmakov 			 * Reinitialize the search context so we can lookup the
145fd9d6367SAnton Altaparmakov 			 * needed attribute extent.
146fd9d6367SAnton Altaparmakov 			 */
147fd9d6367SAnton Altaparmakov 			ntfs_attr_reinit_search_ctx(ctx);
148c49c3111SRichard Knutsson 			ctx_needs_reset = true;
149fd9d6367SAnton Altaparmakov 		}
150fd9d6367SAnton Altaparmakov 	}
151fd9d6367SAnton Altaparmakov 	if (ctx_needs_reset) {
1521da177e4SLinus Torvalds 		err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
1531da177e4SLinus Torvalds 				CASE_SENSITIVE, vcn, NULL, 0, ctx);
1544757d7dfSAnton Altaparmakov 		if (unlikely(err)) {
1554757d7dfSAnton Altaparmakov 			if (err == -ENOENT)
1564757d7dfSAnton Altaparmakov 				err = -EIO;
1574757d7dfSAnton Altaparmakov 			goto err_out;
1584757d7dfSAnton Altaparmakov 		}
159fd9d6367SAnton Altaparmakov 		BUG_ON(!ctx->attr->non_resident);
160fd9d6367SAnton Altaparmakov 	}
1614757d7dfSAnton Altaparmakov 	a = ctx->attr;
1624757d7dfSAnton Altaparmakov 	/*
1634757d7dfSAnton Altaparmakov 	 * Only decompress the mapping pairs if @vcn is inside it.  Otherwise
1644757d7dfSAnton Altaparmakov 	 * we get into problems when we try to map an out of bounds vcn because
1654757d7dfSAnton Altaparmakov 	 * we then try to map the already mapped runlist fragment and
1664757d7dfSAnton Altaparmakov 	 * ntfs_mapping_pairs_decompress() fails.
1674757d7dfSAnton Altaparmakov 	 */
1684757d7dfSAnton Altaparmakov 	end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1;
169ebab8990SAnton Altaparmakov 	if (unlikely(vcn && vcn >= end_vcn)) {
1704757d7dfSAnton Altaparmakov 		err = -ENOENT;
1714757d7dfSAnton Altaparmakov 		goto err_out;
1724757d7dfSAnton Altaparmakov 	}
1734757d7dfSAnton Altaparmakov 	rl = ntfs_mapping_pairs_decompress(ni->vol, a, ni->runlist.rl);
1741da177e4SLinus Torvalds 	if (IS_ERR(rl))
1751da177e4SLinus Torvalds 		err = PTR_ERR(rl);
1761da177e4SLinus Torvalds 	else
1771da177e4SLinus Torvalds 		ni->runlist.rl = rl;
1781da177e4SLinus Torvalds err_out:
179fd9d6367SAnton Altaparmakov 	if (ctx_is_temporary) {
1804757d7dfSAnton Altaparmakov 		if (likely(ctx))
1814757d7dfSAnton Altaparmakov 			ntfs_attr_put_search_ctx(ctx);
1821da177e4SLinus Torvalds 		unmap_mft_record(base_ni);
183fd9d6367SAnton Altaparmakov 	} else if (ctx_needs_reset) {
184fd9d6367SAnton Altaparmakov 		/*
185fd9d6367SAnton Altaparmakov 		 * If there is no attribute list, restoring the search context
18625985edcSLucas De Marchi 		 * is accomplished simply by copying the saved context back over
187fd9d6367SAnton Altaparmakov 		 * the caller supplied context.  If there is an attribute list,
188fd9d6367SAnton Altaparmakov 		 * things are more complicated as we need to deal with mapping
189fd9d6367SAnton Altaparmakov 		 * of mft records and resulting potential changes in pointers.
190fd9d6367SAnton Altaparmakov 		 */
191fd9d6367SAnton Altaparmakov 		if (NInoAttrList(base_ni)) {
192fd9d6367SAnton Altaparmakov 			/*
193fd9d6367SAnton Altaparmakov 			 * If the currently mapped (extent) inode is not the
194fd9d6367SAnton Altaparmakov 			 * one we had before, we need to unmap it and map the
195fd9d6367SAnton Altaparmakov 			 * old one.
196fd9d6367SAnton Altaparmakov 			 */
197fd9d6367SAnton Altaparmakov 			if (ctx->ntfs_ino != old_ctx.ntfs_ino) {
198fd9d6367SAnton Altaparmakov 				/*
199fd9d6367SAnton Altaparmakov 				 * If the currently mapped inode is not the
200fd9d6367SAnton Altaparmakov 				 * base inode, unmap it.
201fd9d6367SAnton Altaparmakov 				 */
202fd9d6367SAnton Altaparmakov 				if (ctx->base_ntfs_ino && ctx->ntfs_ino !=
203fd9d6367SAnton Altaparmakov 						ctx->base_ntfs_ino) {
204fd9d6367SAnton Altaparmakov 					unmap_extent_mft_record(ctx->ntfs_ino);
205fd9d6367SAnton Altaparmakov 					ctx->mrec = ctx->base_mrec;
206fd9d6367SAnton Altaparmakov 					BUG_ON(!ctx->mrec);
207fd9d6367SAnton Altaparmakov 				}
208fd9d6367SAnton Altaparmakov 				/*
209fd9d6367SAnton Altaparmakov 				 * If the old mapped inode is not the base
210fd9d6367SAnton Altaparmakov 				 * inode, map it.
211fd9d6367SAnton Altaparmakov 				 */
212fd9d6367SAnton Altaparmakov 				if (old_ctx.base_ntfs_ino &&
213fd9d6367SAnton Altaparmakov 						old_ctx.ntfs_ino !=
214fd9d6367SAnton Altaparmakov 						old_ctx.base_ntfs_ino) {
215fd9d6367SAnton Altaparmakov retry_map:
216fd9d6367SAnton Altaparmakov 					ctx->mrec = map_mft_record(
217fd9d6367SAnton Altaparmakov 							old_ctx.ntfs_ino);
218fd9d6367SAnton Altaparmakov 					/*
219fd9d6367SAnton Altaparmakov 					 * Something bad has happened.  If out
220fd9d6367SAnton Altaparmakov 					 * of memory retry till it succeeds.
221fd9d6367SAnton Altaparmakov 					 * Any other errors are fatal and we
222fd9d6367SAnton Altaparmakov 					 * return the error code in ctx->mrec.
223fd9d6367SAnton Altaparmakov 					 * Let the caller deal with it...  We
224fd9d6367SAnton Altaparmakov 					 * just need to fudge things so the
225fd9d6367SAnton Altaparmakov 					 * caller can reinit and/or put the
226fd9d6367SAnton Altaparmakov 					 * search context safely.
227fd9d6367SAnton Altaparmakov 					 */
228fd9d6367SAnton Altaparmakov 					if (IS_ERR(ctx->mrec)) {
229fd9d6367SAnton Altaparmakov 						if (PTR_ERR(ctx->mrec) ==
230fd9d6367SAnton Altaparmakov 								-ENOMEM) {
231fd9d6367SAnton Altaparmakov 							schedule();
232fd9d6367SAnton Altaparmakov 							goto retry_map;
233fd9d6367SAnton Altaparmakov 						} else
234fd9d6367SAnton Altaparmakov 							old_ctx.ntfs_ino =
235fd9d6367SAnton Altaparmakov 								old_ctx.
236fd9d6367SAnton Altaparmakov 								base_ntfs_ino;
237fd9d6367SAnton Altaparmakov 					}
238fd9d6367SAnton Altaparmakov 				}
239fd9d6367SAnton Altaparmakov 			}
240fd9d6367SAnton Altaparmakov 			/* Update the changed pointers in the saved context. */
241fd9d6367SAnton Altaparmakov 			if (ctx->mrec != old_ctx.mrec) {
242fd9d6367SAnton Altaparmakov 				if (!IS_ERR(ctx->mrec))
243fd9d6367SAnton Altaparmakov 					old_ctx.attr = (ATTR_RECORD*)(
244fd9d6367SAnton Altaparmakov 							(u8*)ctx->mrec +
245fd9d6367SAnton Altaparmakov 							((u8*)old_ctx.attr -
246fd9d6367SAnton Altaparmakov 							(u8*)old_ctx.mrec));
247fd9d6367SAnton Altaparmakov 				old_ctx.mrec = ctx->mrec;
248fd9d6367SAnton Altaparmakov 			}
249fd9d6367SAnton Altaparmakov 		}
250fd9d6367SAnton Altaparmakov 		/* Restore the search context to the saved one. */
251fd9d6367SAnton Altaparmakov 		*ctx = old_ctx;
252fd9d6367SAnton Altaparmakov 		/*
253fd9d6367SAnton Altaparmakov 		 * We drop the reference on the page we took earlier.  In the
254fd9d6367SAnton Altaparmakov 		 * case that IS_ERR(ctx->mrec) is true this means we might lose
255fd9d6367SAnton Altaparmakov 		 * some changes to the mft record that had been made between
256fd9d6367SAnton Altaparmakov 		 * the last time it was marked dirty/written out and now.  This
257fd9d6367SAnton Altaparmakov 		 * at this stage is not a problem as the mapping error is fatal
258fd9d6367SAnton Altaparmakov 		 * enough that the mft record cannot be written out anyway and
259fd9d6367SAnton Altaparmakov 		 * the caller is very likely to shutdown the whole inode
260fd9d6367SAnton Altaparmakov 		 * immediately and mark the volume dirty for chkdsk to pick up
261fd9d6367SAnton Altaparmakov 		 * the pieces anyway.
262fd9d6367SAnton Altaparmakov 		 */
263fd9d6367SAnton Altaparmakov 		if (put_this_page)
26409cbfeafSKirill A. Shutemov 			put_page(put_this_page);
265fd9d6367SAnton Altaparmakov 	}
2661da177e4SLinus Torvalds 	return err;
2671da177e4SLinus Torvalds }
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds /**
270b6ad6c52SAnton Altaparmakov  * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode
271b6ad6c52SAnton Altaparmakov  * @ni:		ntfs inode for which to map (part of) a runlist
272b6ad6c52SAnton Altaparmakov  * @vcn:	map runlist part containing this vcn
273b6ad6c52SAnton Altaparmakov  *
274b6ad6c52SAnton Altaparmakov  * Map the part of a runlist containing the @vcn of the ntfs inode @ni.
275b6ad6c52SAnton Altaparmakov  *
2764757d7dfSAnton Altaparmakov  * Return 0 on success and -errno on error.  There is one special error code
2774757d7dfSAnton Altaparmakov  * which is not an error as such.  This is -ENOENT.  It means that @vcn is out
2784757d7dfSAnton Altaparmakov  * of bounds of the runlist.
279b6ad6c52SAnton Altaparmakov  *
280b6ad6c52SAnton Altaparmakov  * Locking: - The runlist must be unlocked on entry and is unlocked on return.
281fd9d6367SAnton Altaparmakov  *	    - This function takes the runlist lock for writing and may modify
282fd9d6367SAnton Altaparmakov  *	      the runlist.
283b6ad6c52SAnton Altaparmakov  */
ntfs_map_runlist(ntfs_inode * ni,VCN vcn)284b6ad6c52SAnton Altaparmakov int ntfs_map_runlist(ntfs_inode *ni, VCN vcn)
285b6ad6c52SAnton Altaparmakov {
286b6ad6c52SAnton Altaparmakov 	int err = 0;
287b6ad6c52SAnton Altaparmakov 
288b6ad6c52SAnton Altaparmakov 	down_write(&ni->runlist.lock);
289b6ad6c52SAnton Altaparmakov 	/* Make sure someone else didn't do the work while we were sleeping. */
290b6ad6c52SAnton Altaparmakov 	if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <=
291b6ad6c52SAnton Altaparmakov 			LCN_RL_NOT_MAPPED))
292fd9d6367SAnton Altaparmakov 		err = ntfs_map_runlist_nolock(ni, vcn, NULL);
293b6ad6c52SAnton Altaparmakov 	up_write(&ni->runlist.lock);
294b6ad6c52SAnton Altaparmakov 	return err;
295b6ad6c52SAnton Altaparmakov }
296b6ad6c52SAnton Altaparmakov 
297b6ad6c52SAnton Altaparmakov /**
298271849a9SAnton Altaparmakov  * ntfs_attr_vcn_to_lcn_nolock - convert a vcn into a lcn given an ntfs inode
299271849a9SAnton Altaparmakov  * @ni:			ntfs inode of the attribute whose runlist to search
300271849a9SAnton Altaparmakov  * @vcn:		vcn to convert
301271849a9SAnton Altaparmakov  * @write_locked:	true if the runlist is locked for writing
302271849a9SAnton Altaparmakov  *
303271849a9SAnton Altaparmakov  * Find the virtual cluster number @vcn in the runlist of the ntfs attribute
304271849a9SAnton Altaparmakov  * described by the ntfs inode @ni and return the corresponding logical cluster
305271849a9SAnton Altaparmakov  * number (lcn).
306271849a9SAnton Altaparmakov  *
307271849a9SAnton Altaparmakov  * If the @vcn is not mapped yet, the attempt is made to map the attribute
308271849a9SAnton Altaparmakov  * extent containing the @vcn and the vcn to lcn conversion is retried.
309271849a9SAnton Altaparmakov  *
310271849a9SAnton Altaparmakov  * If @write_locked is true the caller has locked the runlist for writing and
311271849a9SAnton Altaparmakov  * if false for reading.
312271849a9SAnton Altaparmakov  *
313271849a9SAnton Altaparmakov  * Since lcns must be >= 0, we use negative return codes with special meaning:
314271849a9SAnton Altaparmakov  *
315271849a9SAnton Altaparmakov  * Return code	Meaning / Description
316271849a9SAnton Altaparmakov  * ==========================================
317271849a9SAnton Altaparmakov  *  LCN_HOLE	Hole / not allocated on disk.
318271849a9SAnton Altaparmakov  *  LCN_ENOENT	There is no such vcn in the runlist, i.e. @vcn is out of bounds.
319271849a9SAnton Altaparmakov  *  LCN_ENOMEM	Not enough memory to map runlist.
320271849a9SAnton Altaparmakov  *  LCN_EIO	Critical error (runlist/file is corrupt, i/o error, etc).
321271849a9SAnton Altaparmakov  *
322271849a9SAnton Altaparmakov  * Locking: - The runlist must be locked on entry and is left locked on return.
323c49c3111SRichard Knutsson  *	    - If @write_locked is 'false', i.e. the runlist is locked for reading,
324271849a9SAnton Altaparmakov  *	      the lock may be dropped inside the function so you cannot rely on
325271849a9SAnton Altaparmakov  *	      the runlist still being the same when this function returns.
326271849a9SAnton Altaparmakov  */
ntfs_attr_vcn_to_lcn_nolock(ntfs_inode * ni,const VCN vcn,const bool write_locked)327271849a9SAnton Altaparmakov LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
328c49c3111SRichard Knutsson 		const bool write_locked)
329271849a9SAnton Altaparmakov {
330271849a9SAnton Altaparmakov 	LCN lcn;
3312983d1bdSAnton Altaparmakov 	unsigned long flags;
332c49c3111SRichard Knutsson 	bool is_retry = false;
333271849a9SAnton Altaparmakov 
33445d95bcdSAnton Altaparmakov 	BUG_ON(!ni);
335271849a9SAnton Altaparmakov 	ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.",
336271849a9SAnton Altaparmakov 			ni->mft_no, (unsigned long long)vcn,
337271849a9SAnton Altaparmakov 			write_locked ? "write" : "read");
338271849a9SAnton Altaparmakov 	BUG_ON(!NInoNonResident(ni));
339271849a9SAnton Altaparmakov 	BUG_ON(vcn < 0);
3402983d1bdSAnton Altaparmakov 	if (!ni->runlist.rl) {
3412983d1bdSAnton Altaparmakov 		read_lock_irqsave(&ni->size_lock, flags);
3422983d1bdSAnton Altaparmakov 		if (!ni->allocated_size) {
3432983d1bdSAnton Altaparmakov 			read_unlock_irqrestore(&ni->size_lock, flags);
3442983d1bdSAnton Altaparmakov 			return LCN_ENOENT;
3452983d1bdSAnton Altaparmakov 		}
3462983d1bdSAnton Altaparmakov 		read_unlock_irqrestore(&ni->size_lock, flags);
3472983d1bdSAnton Altaparmakov 	}
348271849a9SAnton Altaparmakov retry_remap:
349271849a9SAnton Altaparmakov 	/* Convert vcn to lcn.  If that fails map the runlist and retry once. */
350271849a9SAnton Altaparmakov 	lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn);
351271849a9SAnton Altaparmakov 	if (likely(lcn >= LCN_HOLE)) {
352271849a9SAnton Altaparmakov 		ntfs_debug("Done, lcn 0x%llx.", (long long)lcn);
353271849a9SAnton Altaparmakov 		return lcn;
354271849a9SAnton Altaparmakov 	}
355271849a9SAnton Altaparmakov 	if (lcn != LCN_RL_NOT_MAPPED) {
356271849a9SAnton Altaparmakov 		if (lcn != LCN_ENOENT)
357271849a9SAnton Altaparmakov 			lcn = LCN_EIO;
358271849a9SAnton Altaparmakov 	} else if (!is_retry) {
359271849a9SAnton Altaparmakov 		int err;
360271849a9SAnton Altaparmakov 
361271849a9SAnton Altaparmakov 		if (!write_locked) {
362271849a9SAnton Altaparmakov 			up_read(&ni->runlist.lock);
363271849a9SAnton Altaparmakov 			down_write(&ni->runlist.lock);
364271849a9SAnton Altaparmakov 			if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) !=
365271849a9SAnton Altaparmakov 					LCN_RL_NOT_MAPPED)) {
366271849a9SAnton Altaparmakov 				up_write(&ni->runlist.lock);
367271849a9SAnton Altaparmakov 				down_read(&ni->runlist.lock);
368271849a9SAnton Altaparmakov 				goto retry_remap;
369271849a9SAnton Altaparmakov 			}
370271849a9SAnton Altaparmakov 		}
371fd9d6367SAnton Altaparmakov 		err = ntfs_map_runlist_nolock(ni, vcn, NULL);
372271849a9SAnton Altaparmakov 		if (!write_locked) {
373271849a9SAnton Altaparmakov 			up_write(&ni->runlist.lock);
374271849a9SAnton Altaparmakov 			down_read(&ni->runlist.lock);
375271849a9SAnton Altaparmakov 		}
376271849a9SAnton Altaparmakov 		if (likely(!err)) {
377c49c3111SRichard Knutsson 			is_retry = true;
378271849a9SAnton Altaparmakov 			goto retry_remap;
379271849a9SAnton Altaparmakov 		}
380271849a9SAnton Altaparmakov 		if (err == -ENOENT)
381271849a9SAnton Altaparmakov 			lcn = LCN_ENOENT;
382271849a9SAnton Altaparmakov 		else if (err == -ENOMEM)
383271849a9SAnton Altaparmakov 			lcn = LCN_ENOMEM;
384271849a9SAnton Altaparmakov 		else
385271849a9SAnton Altaparmakov 			lcn = LCN_EIO;
386271849a9SAnton Altaparmakov 	}
387271849a9SAnton Altaparmakov 	if (lcn != LCN_ENOENT)
388271849a9SAnton Altaparmakov 		ntfs_error(ni->vol->sb, "Failed with error code %lli.",
389271849a9SAnton Altaparmakov 				(long long)lcn);
390271849a9SAnton Altaparmakov 	return lcn;
391271849a9SAnton Altaparmakov }
392271849a9SAnton Altaparmakov 
393271849a9SAnton Altaparmakov /**
394c0c1cc0eSAnton Altaparmakov  * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode
3951da177e4SLinus Torvalds  * @ni:		ntfs inode describing the runlist to search
3961da177e4SLinus Torvalds  * @vcn:	vcn to find
39769b41e3cSAnton Altaparmakov  * @ctx:	active attribute search context if present or NULL if not
3981da177e4SLinus Torvalds  *
3991da177e4SLinus Torvalds  * Find the virtual cluster number @vcn in the runlist described by the ntfs
4001da177e4SLinus Torvalds  * inode @ni and return the address of the runlist element containing the @vcn.
401b6ad6c52SAnton Altaparmakov  *
402c0c1cc0eSAnton Altaparmakov  * If the @vcn is not mapped yet, the attempt is made to map the attribute
403c0c1cc0eSAnton Altaparmakov  * extent containing the @vcn and the vcn to lcn conversion is retried.
404c0c1cc0eSAnton Altaparmakov  *
40569b41e3cSAnton Altaparmakov  * If @ctx is specified, it is an active search context of @ni and its base mft
40669b41e3cSAnton Altaparmakov  * record.  This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped
40769b41e3cSAnton Altaparmakov  * runlist fragments and allows their mapping.  If you do not have the mft
40869b41e3cSAnton Altaparmakov  * record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock()
40969b41e3cSAnton Altaparmakov  * will perform the necessary mapping and unmapping.
4101da177e4SLinus Torvalds  *
41169b41e3cSAnton Altaparmakov  * Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and
41269b41e3cSAnton Altaparmakov  * restores it before returning.  Thus, @ctx will be left pointing to the same
41369b41e3cSAnton Altaparmakov  * attribute on return as on entry.  However, the actual pointers in @ctx may
41469b41e3cSAnton Altaparmakov  * point to different memory locations on return, so you must remember to reset
41569b41e3cSAnton Altaparmakov  * any cached pointers from the @ctx, i.e. after the call to
41669b41e3cSAnton Altaparmakov  * ntfs_attr_find_vcn_nolock(), you will probably want to do:
41769b41e3cSAnton Altaparmakov  *	m = ctx->mrec;
41869b41e3cSAnton Altaparmakov  *	a = ctx->attr;
41969b41e3cSAnton Altaparmakov  * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
42069b41e3cSAnton Altaparmakov  * you cache ctx->mrec in a variable @m of type MFT_RECORD *.
4211da177e4SLinus Torvalds  * Note you need to distinguish between the lcn of the returned runlist element
4221da177e4SLinus Torvalds  * being >= 0 and LCN_HOLE.  In the later case you have to return zeroes on
4231da177e4SLinus Torvalds  * read and allocate clusters on write.
4241da177e4SLinus Torvalds  *
4251da177e4SLinus Torvalds  * Return the runlist element containing the @vcn on success and
4261da177e4SLinus Torvalds  * ERR_PTR(-errno) on error.  You need to test the return value with IS_ERR()
4271da177e4SLinus Torvalds  * to decide if the return is success or failure and PTR_ERR() to get to the
4281da177e4SLinus Torvalds  * error code if IS_ERR() is true.
4291da177e4SLinus Torvalds  *
4301da177e4SLinus Torvalds  * The possible error return codes are:
4311da177e4SLinus Torvalds  *	-ENOENT - No such vcn in the runlist, i.e. @vcn is out of bounds.
4321da177e4SLinus Torvalds  *	-ENOMEM - Not enough memory to map runlist.
4331da177e4SLinus Torvalds  *	-EIO	- Critical error (runlist/file is corrupt, i/o error, etc).
4341da177e4SLinus Torvalds  *
43569b41e3cSAnton Altaparmakov  * WARNING: If @ctx is supplied, regardless of whether success or failure is
436c49c3111SRichard Knutsson  *	    returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
43769b41e3cSAnton Altaparmakov  *	    is no longer valid, i.e. you need to either call
43869b41e3cSAnton Altaparmakov  *	    ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
43969b41e3cSAnton Altaparmakov  *	    In that case PTR_ERR(@ctx->mrec) will give you the error code for
44069b41e3cSAnton Altaparmakov  *	    why the mapping of the old inode failed.
44169b41e3cSAnton Altaparmakov  *
44269b41e3cSAnton Altaparmakov  * Locking: - The runlist described by @ni must be locked for writing on entry
44369b41e3cSAnton Altaparmakov  *	      and is locked on return.  Note the runlist may be modified when
44469b41e3cSAnton Altaparmakov  *	      needed runlist fragments need to be mapped.
44569b41e3cSAnton Altaparmakov  *	    - If @ctx is NULL, the base mft record of @ni must not be mapped on
44669b41e3cSAnton Altaparmakov  *	      entry and it will be left unmapped on return.
44769b41e3cSAnton Altaparmakov  *	    - If @ctx is not NULL, the base mft record must be mapped on entry
44869b41e3cSAnton Altaparmakov  *	      and it will be left mapped on return.
4491da177e4SLinus Torvalds  */
ntfs_attr_find_vcn_nolock(ntfs_inode * ni,const VCN vcn,ntfs_attr_search_ctx * ctx)450c0c1cc0eSAnton Altaparmakov runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,
45169b41e3cSAnton Altaparmakov 		ntfs_attr_search_ctx *ctx)
4521da177e4SLinus Torvalds {
4532983d1bdSAnton Altaparmakov 	unsigned long flags;
4541da177e4SLinus Torvalds 	runlist_element *rl;
4551da177e4SLinus Torvalds 	int err = 0;
456c49c3111SRichard Knutsson 	bool is_retry = false;
4571da177e4SLinus Torvalds 
45845d95bcdSAnton Altaparmakov 	BUG_ON(!ni);
45969b41e3cSAnton Altaparmakov 	ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.",
46069b41e3cSAnton Altaparmakov 			ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out");
4611da177e4SLinus Torvalds 	BUG_ON(!NInoNonResident(ni));
4621da177e4SLinus Torvalds 	BUG_ON(vcn < 0);
4632983d1bdSAnton Altaparmakov 	if (!ni->runlist.rl) {
4642983d1bdSAnton Altaparmakov 		read_lock_irqsave(&ni->size_lock, flags);
4652983d1bdSAnton Altaparmakov 		if (!ni->allocated_size) {
4662983d1bdSAnton Altaparmakov 			read_unlock_irqrestore(&ni->size_lock, flags);
4672983d1bdSAnton Altaparmakov 			return ERR_PTR(-ENOENT);
4682983d1bdSAnton Altaparmakov 		}
4692983d1bdSAnton Altaparmakov 		read_unlock_irqrestore(&ni->size_lock, flags);
4702983d1bdSAnton Altaparmakov 	}
471b6ad6c52SAnton Altaparmakov retry_remap:
4721da177e4SLinus Torvalds 	rl = ni->runlist.rl;
4731da177e4SLinus Torvalds 	if (likely(rl && vcn >= rl[0].vcn)) {
4741da177e4SLinus Torvalds 		while (likely(rl->length)) {
475b6ad6c52SAnton Altaparmakov 			if (unlikely(vcn < rl[1].vcn)) {
4761da177e4SLinus Torvalds 				if (likely(rl->lcn >= LCN_HOLE)) {
4771da177e4SLinus Torvalds 					ntfs_debug("Done.");
4781da177e4SLinus Torvalds 					return rl;
4791da177e4SLinus Torvalds 				}
4801da177e4SLinus Torvalds 				break;
4811da177e4SLinus Torvalds 			}
4821da177e4SLinus Torvalds 			rl++;
4831da177e4SLinus Torvalds 		}
4841da177e4SLinus Torvalds 		if (likely(rl->lcn != LCN_RL_NOT_MAPPED)) {
4851da177e4SLinus Torvalds 			if (likely(rl->lcn == LCN_ENOENT))
4861da177e4SLinus Torvalds 				err = -ENOENT;
4871da177e4SLinus Torvalds 			else
4881da177e4SLinus Torvalds 				err = -EIO;
4891da177e4SLinus Torvalds 		}
4901da177e4SLinus Torvalds 	}
4911da177e4SLinus Torvalds 	if (!err && !is_retry) {
4921da177e4SLinus Torvalds 		/*
49369b41e3cSAnton Altaparmakov 		 * If the search context is invalid we cannot map the unmapped
49469b41e3cSAnton Altaparmakov 		 * region.
4951da177e4SLinus Torvalds 		 */
49669b41e3cSAnton Altaparmakov 		if (IS_ERR(ctx->mrec))
49769b41e3cSAnton Altaparmakov 			err = PTR_ERR(ctx->mrec);
49869b41e3cSAnton Altaparmakov 		else {
49969b41e3cSAnton Altaparmakov 			/*
50069b41e3cSAnton Altaparmakov 			 * The @vcn is in an unmapped region, map the runlist
50169b41e3cSAnton Altaparmakov 			 * and retry.
50269b41e3cSAnton Altaparmakov 			 */
50369b41e3cSAnton Altaparmakov 			err = ntfs_map_runlist_nolock(ni, vcn, ctx);
5041da177e4SLinus Torvalds 			if (likely(!err)) {
505c49c3111SRichard Knutsson 				is_retry = true;
506b6ad6c52SAnton Altaparmakov 				goto retry_remap;
5071da177e4SLinus Torvalds 			}
50869b41e3cSAnton Altaparmakov 		}
5094757d7dfSAnton Altaparmakov 		if (err == -EINVAL)
5101da177e4SLinus Torvalds 			err = -EIO;
5111da177e4SLinus Torvalds 	} else if (!err)
5121da177e4SLinus Torvalds 		err = -EIO;
513b6ad6c52SAnton Altaparmakov 	if (err != -ENOENT)
5141da177e4SLinus Torvalds 		ntfs_error(ni->vol->sb, "Failed with error code %i.", err);
5151da177e4SLinus Torvalds 	return ERR_PTR(err);
5161da177e4SLinus Torvalds }
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds /**
5191da177e4SLinus Torvalds  * ntfs_attr_find - find (next) attribute in mft record
5201da177e4SLinus Torvalds  * @type:	attribute type to find
5211da177e4SLinus Torvalds  * @name:	attribute name to find (optional, i.e. NULL means don't care)
5221da177e4SLinus Torvalds  * @name_len:	attribute name length (only needed if @name present)
5231da177e4SLinus Torvalds  * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
5241da177e4SLinus Torvalds  * @val:	attribute value to find (optional, resident attributes only)
5251da177e4SLinus Torvalds  * @val_len:	attribute value length
5261da177e4SLinus Torvalds  * @ctx:	search context with mft record and attribute to search from
5271da177e4SLinus Torvalds  *
5281da177e4SLinus Torvalds  * You should not need to call this function directly.  Use ntfs_attr_lookup()
5291da177e4SLinus Torvalds  * instead.
5301da177e4SLinus Torvalds  *
5311da177e4SLinus Torvalds  * ntfs_attr_find() takes a search context @ctx as parameter and searches the
5321da177e4SLinus Torvalds  * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an
5331da177e4SLinus Torvalds  * attribute of @type, optionally @name and @val.
5341da177e4SLinus Torvalds  *
5351da177e4SLinus Torvalds  * If the attribute is found, ntfs_attr_find() returns 0 and @ctx->attr will
5361da177e4SLinus Torvalds  * point to the found attribute.
5371da177e4SLinus Torvalds  *
5381da177e4SLinus Torvalds  * If the attribute is not found, ntfs_attr_find() returns -ENOENT and
5391da177e4SLinus Torvalds  * @ctx->attr will point to the attribute before which the attribute being
5401da177e4SLinus Torvalds  * searched for would need to be inserted if such an action were to be desired.
5411da177e4SLinus Torvalds  *
5421da177e4SLinus Torvalds  * On actual error, ntfs_attr_find() returns -EIO.  In this case @ctx->attr is
5431da177e4SLinus Torvalds  * undefined and in particular do not rely on it not changing.
5441da177e4SLinus Torvalds  *
545c49c3111SRichard Knutsson  * If @ctx->is_first is 'true', the search begins with @ctx->attr itself.  If it
546c49c3111SRichard Knutsson  * is 'false', the search begins after @ctx->attr.
5471da177e4SLinus Torvalds  *
5481da177e4SLinus Torvalds  * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and
5491da177e4SLinus Torvalds  * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record
5501da177e4SLinus Torvalds  * @ctx->mrec belongs.  This is so we can get at the ntfs volume and hence at
5511da177e4SLinus Torvalds  * the upcase table.  If @ic is CASE_SENSITIVE, the comparison is case
5521da177e4SLinus Torvalds  * sensitive.  When @name is present, @name_len is the @name length in Unicode
5531da177e4SLinus Torvalds  * characters.
5541da177e4SLinus Torvalds  *
5551da177e4SLinus Torvalds  * If @name is not present (NULL), we assume that the unnamed attribute is
5561da177e4SLinus Torvalds  * being searched for.
5571da177e4SLinus Torvalds  *
5581da177e4SLinus Torvalds  * Finally, the resident attribute value @val is looked for, if present.  If
5591da177e4SLinus Torvalds  * @val is not present (NULL), @val_len is ignored.
5601da177e4SLinus Torvalds  *
5611da177e4SLinus Torvalds  * ntfs_attr_find() only searches the specified mft record and it ignores the
5621da177e4SLinus Torvalds  * presence of an attribute list attribute (unless it is the one being searched
5631da177e4SLinus Torvalds  * for, obviously).  If you need to take attribute lists into consideration,
5641da177e4SLinus Torvalds  * use ntfs_attr_lookup() instead (see below).  This also means that you cannot
5651da177e4SLinus Torvalds  * use ntfs_attr_find() to search for extent records of non-resident
5661da177e4SLinus Torvalds  * attributes, as extents with lowest_vcn != 0 are usually described by the
5671da177e4SLinus Torvalds  * attribute list attribute only. - Note that it is possible that the first
5681da177e4SLinus Torvalds  * extent is only in the attribute list while the last extent is in the base
5691da177e4SLinus Torvalds  * mft record, so do not rely on being able to find the first extent in the
5701da177e4SLinus Torvalds  * base mft record.
5711da177e4SLinus Torvalds  *
5721da177e4SLinus Torvalds  * Warning: Never use @val when looking for attribute types which can be
5731da177e4SLinus Torvalds  *	    non-resident as this most likely will result in a crash!
5741da177e4SLinus Torvalds  */
ntfs_attr_find(const ATTR_TYPE type,const ntfschar * name,const u32 name_len,const IGNORE_CASE_BOOL ic,const u8 * val,const u32 val_len,ntfs_attr_search_ctx * ctx)5751da177e4SLinus Torvalds static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name,
5761da177e4SLinus Torvalds 		const u32 name_len, const IGNORE_CASE_BOOL ic,
5771da177e4SLinus Torvalds 		const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx)
5781da177e4SLinus Torvalds {
5791da177e4SLinus Torvalds 	ATTR_RECORD *a;
5801da177e4SLinus Torvalds 	ntfs_volume *vol = ctx->ntfs_ino->vol;
5811da177e4SLinus Torvalds 	ntfschar *upcase = vol->upcase;
5821da177e4SLinus Torvalds 	u32 upcase_len = vol->upcase_len;
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds 	/*
5851da177e4SLinus Torvalds 	 * Iterate over attributes in mft record starting at @ctx->attr, or the
586c49c3111SRichard Knutsson 	 * attribute following that, if @ctx->is_first is 'true'.
5871da177e4SLinus Torvalds 	 */
5881da177e4SLinus Torvalds 	if (ctx->is_first) {
5891da177e4SLinus Torvalds 		a = ctx->attr;
590c49c3111SRichard Knutsson 		ctx->is_first = false;
5911da177e4SLinus Torvalds 	} else
5921da177e4SLinus Torvalds 		a = (ATTR_RECORD*)((u8*)ctx->attr +
5931da177e4SLinus Torvalds 				le32_to_cpu(ctx->attr->length));
5941da177e4SLinus Torvalds 	for (;;	a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) {
59538c9c22aSChenXiaoSong 		u8 *mrec_end = (u8 *)ctx->mrec +
59638c9c22aSChenXiaoSong 		               le32_to_cpu(ctx->mrec->bytes_allocated);
59736a4d82dSHawkins Jiawei 		u8 *name_end;
59836a4d82dSHawkins Jiawei 
59936a4d82dSHawkins Jiawei 		/* check whether ATTR_RECORD wrap */
60036a4d82dSHawkins Jiawei 		if ((u8 *)a < (u8 *)ctx->mrec)
6011da177e4SLinus Torvalds 			break;
60236a4d82dSHawkins Jiawei 
60336a4d82dSHawkins Jiawei 		/* check whether Attribute Record Header is within bounds */
60436a4d82dSHawkins Jiawei 		if ((u8 *)a > mrec_end ||
60536a4d82dSHawkins Jiawei 		    (u8 *)a + sizeof(ATTR_RECORD) > mrec_end)
60636a4d82dSHawkins Jiawei 			break;
60736a4d82dSHawkins Jiawei 
60836a4d82dSHawkins Jiawei 		/* check whether ATTR_RECORD's name is within bounds */
60936a4d82dSHawkins Jiawei 		name_end = (u8 *)a + le16_to_cpu(a->name_offset) +
61036a4d82dSHawkins Jiawei 			   a->name_length * sizeof(ntfschar);
61136a4d82dSHawkins Jiawei 		if (name_end > mrec_end)
61236a4d82dSHawkins Jiawei 			break;
61336a4d82dSHawkins Jiawei 
6141da177e4SLinus Torvalds 		ctx->attr = a;
6151da177e4SLinus Torvalds 		if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) ||
6161da177e4SLinus Torvalds 				a->type == AT_END))
6171da177e4SLinus Torvalds 			return -ENOENT;
6181da177e4SLinus Torvalds 		if (unlikely(!a->length))
6191da177e4SLinus Torvalds 			break;
62063095f4fSHawkins Jiawei 
62163095f4fSHawkins Jiawei 		/* check whether ATTR_RECORD's length wrap */
62263095f4fSHawkins Jiawei 		if ((u8 *)a + le32_to_cpu(a->length) < (u8 *)a)
62363095f4fSHawkins Jiawei 			break;
62463095f4fSHawkins Jiawei 		/* check whether ATTR_RECORD's length is within bounds */
62563095f4fSHawkins Jiawei 		if ((u8 *)a + le32_to_cpu(a->length) > mrec_end)
62663095f4fSHawkins Jiawei 			break;
62763095f4fSHawkins Jiawei 
6281da177e4SLinus Torvalds 		if (a->type != type)
6291da177e4SLinus Torvalds 			continue;
6301da177e4SLinus Torvalds 		/*
6311da177e4SLinus Torvalds 		 * If @name is present, compare the two names.  If @name is
6321da177e4SLinus Torvalds 		 * missing, assume we want an unnamed attribute.
6331da177e4SLinus Torvalds 		 */
6341da177e4SLinus Torvalds 		if (!name) {
6351da177e4SLinus Torvalds 			/* The search failed if the found attribute is named. */
6361da177e4SLinus Torvalds 			if (a->name_length)
6371da177e4SLinus Torvalds 				return -ENOENT;
6381da177e4SLinus Torvalds 		} else if (!ntfs_are_names_equal(name, name_len,
6391da177e4SLinus Torvalds 			    (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
6401da177e4SLinus Torvalds 			    a->name_length, ic, upcase, upcase_len)) {
6411da177e4SLinus Torvalds 			register int rc;
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 			rc = ntfs_collate_names(name, name_len,
6441da177e4SLinus Torvalds 					(ntfschar*)((u8*)a +
6451da177e4SLinus Torvalds 					le16_to_cpu(a->name_offset)),
6461da177e4SLinus Torvalds 					a->name_length, 1, IGNORE_CASE,
6471da177e4SLinus Torvalds 					upcase, upcase_len);
6481da177e4SLinus Torvalds 			/*
6491da177e4SLinus Torvalds 			 * If @name collates before a->name, there is no
6501da177e4SLinus Torvalds 			 * matching attribute.
6511da177e4SLinus Torvalds 			 */
6521da177e4SLinus Torvalds 			if (rc == -1)
6531da177e4SLinus Torvalds 				return -ENOENT;
6541da177e4SLinus Torvalds 			/* If the strings are not equal, continue search. */
6551da177e4SLinus Torvalds 			if (rc)
6561da177e4SLinus Torvalds 				continue;
6571da177e4SLinus Torvalds 			rc = ntfs_collate_names(name, name_len,
6581da177e4SLinus Torvalds 					(ntfschar*)((u8*)a +
6591da177e4SLinus Torvalds 					le16_to_cpu(a->name_offset)),
6601da177e4SLinus Torvalds 					a->name_length, 1, CASE_SENSITIVE,
6611da177e4SLinus Torvalds 					upcase, upcase_len);
6621da177e4SLinus Torvalds 			if (rc == -1)
6631da177e4SLinus Torvalds 				return -ENOENT;
6641da177e4SLinus Torvalds 			if (rc)
6651da177e4SLinus Torvalds 				continue;
6661da177e4SLinus Torvalds 		}
6671da177e4SLinus Torvalds 		/*
6681da177e4SLinus Torvalds 		 * The names match or @name not present and attribute is
6691da177e4SLinus Torvalds 		 * unnamed.  If no @val specified, we have found the attribute
6701da177e4SLinus Torvalds 		 * and are done.
6711da177e4SLinus Torvalds 		 */
6721da177e4SLinus Torvalds 		if (!val)
6731da177e4SLinus Torvalds 			return 0;
6741da177e4SLinus Torvalds 		/* @val is present; compare values. */
6751da177e4SLinus Torvalds 		else {
6761da177e4SLinus Torvalds 			register int rc;
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds 			rc = memcmp(val, (u8*)a + le16_to_cpu(
6791da177e4SLinus Torvalds 					a->data.resident.value_offset),
6801da177e4SLinus Torvalds 					min_t(u32, val_len, le32_to_cpu(
6811da177e4SLinus Torvalds 					a->data.resident.value_length)));
6821da177e4SLinus Torvalds 			/*
6831da177e4SLinus Torvalds 			 * If @val collates before the current attribute's
6841da177e4SLinus Torvalds 			 * value, there is no matching attribute.
6851da177e4SLinus Torvalds 			 */
6861da177e4SLinus Torvalds 			if (!rc) {
6871da177e4SLinus Torvalds 				register u32 avl;
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 				avl = le32_to_cpu(
6901da177e4SLinus Torvalds 						a->data.resident.value_length);
6911da177e4SLinus Torvalds 				if (val_len == avl)
6921da177e4SLinus Torvalds 					return 0;
6931da177e4SLinus Torvalds 				if (val_len < avl)
6941da177e4SLinus Torvalds 					return -ENOENT;
6951da177e4SLinus Torvalds 			} else if (rc < 0)
6961da177e4SLinus Torvalds 				return -ENOENT;
6971da177e4SLinus Torvalds 		}
6981da177e4SLinus Torvalds 	}
6991da177e4SLinus Torvalds 	ntfs_error(vol->sb, "Inode is corrupt.  Run chkdsk.");
7001da177e4SLinus Torvalds 	NVolSetErrors(vol);
7011da177e4SLinus Torvalds 	return -EIO;
7021da177e4SLinus Torvalds }
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds /**
7051da177e4SLinus Torvalds  * load_attribute_list - load an attribute list into memory
7061da177e4SLinus Torvalds  * @vol:		ntfs volume from which to read
7071da177e4SLinus Torvalds  * @runlist:		runlist of the attribute list
7081da177e4SLinus Torvalds  * @al_start:		destination buffer
7091da177e4SLinus Torvalds  * @size:		size of the destination buffer in bytes
7101da177e4SLinus Torvalds  * @initialized_size:	initialized size of the attribute list
7111da177e4SLinus Torvalds  *
7121da177e4SLinus Torvalds  * Walk the runlist @runlist and load all clusters from it copying them into
7131da177e4SLinus Torvalds  * the linear buffer @al. The maximum number of bytes copied to @al is @size
7141da177e4SLinus Torvalds  * bytes. Note, @size does not need to be a multiple of the cluster size. If
7151da177e4SLinus Torvalds  * @initialized_size is less than @size, the region in @al between
7161da177e4SLinus Torvalds  * @initialized_size and @size will be zeroed and not read from disk.
7171da177e4SLinus Torvalds  *
7181da177e4SLinus Torvalds  * Return 0 on success or -errno on error.
7191da177e4SLinus Torvalds  */
load_attribute_list(ntfs_volume * vol,runlist * runlist,u8 * al_start,const s64 size,const s64 initialized_size)7201da177e4SLinus Torvalds int load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start,
7211da177e4SLinus Torvalds 		const s64 size, const s64 initialized_size)
7221da177e4SLinus Torvalds {
7231da177e4SLinus Torvalds 	LCN lcn;
7241da177e4SLinus Torvalds 	u8 *al = al_start;
7251da177e4SLinus Torvalds 	u8 *al_end = al + initialized_size;
7261da177e4SLinus Torvalds 	runlist_element *rl;
7271da177e4SLinus Torvalds 	struct buffer_head *bh;
7281da177e4SLinus Torvalds 	struct super_block *sb;
7291da177e4SLinus Torvalds 	unsigned long block_size;
7301da177e4SLinus Torvalds 	unsigned long block, max_block;
7311da177e4SLinus Torvalds 	int err = 0;
7321da177e4SLinus Torvalds 	unsigned char block_size_bits;
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	ntfs_debug("Entering.");
7351da177e4SLinus Torvalds 	if (!vol || !runlist || !al || size <= 0 || initialized_size < 0 ||
7361da177e4SLinus Torvalds 			initialized_size > size)
7371da177e4SLinus Torvalds 		return -EINVAL;
7381da177e4SLinus Torvalds 	if (!initialized_size) {
7391da177e4SLinus Torvalds 		memset(al, 0, size);
7401da177e4SLinus Torvalds 		return 0;
7411da177e4SLinus Torvalds 	}
7421da177e4SLinus Torvalds 	sb = vol->sb;
7431da177e4SLinus Torvalds 	block_size = sb->s_blocksize;
7441da177e4SLinus Torvalds 	block_size_bits = sb->s_blocksize_bits;
7451da177e4SLinus Torvalds 	down_read(&runlist->lock);
7461da177e4SLinus Torvalds 	rl = runlist->rl;
7472983d1bdSAnton Altaparmakov 	if (!rl) {
7482983d1bdSAnton Altaparmakov 		ntfs_error(sb, "Cannot read attribute list since runlist is "
7492983d1bdSAnton Altaparmakov 				"missing.");
7502983d1bdSAnton Altaparmakov 		goto err_out;
7512983d1bdSAnton Altaparmakov 	}
7521da177e4SLinus Torvalds 	/* Read all clusters specified by the runlist one run at a time. */
7531da177e4SLinus Torvalds 	while (rl->length) {
7541da177e4SLinus Torvalds 		lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn);
7551da177e4SLinus Torvalds 		ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.",
7561da177e4SLinus Torvalds 				(unsigned long long)rl->vcn,
7571da177e4SLinus Torvalds 				(unsigned long long)lcn);
7581da177e4SLinus Torvalds 		/* The attribute list cannot be sparse. */
7591da177e4SLinus Torvalds 		if (lcn < 0) {
7601da177e4SLinus Torvalds 			ntfs_error(sb, "ntfs_rl_vcn_to_lcn() failed.  Cannot "
7611da177e4SLinus Torvalds 					"read attribute list.");
7621da177e4SLinus Torvalds 			goto err_out;
7631da177e4SLinus Torvalds 		}
7641da177e4SLinus Torvalds 		block = lcn << vol->cluster_size_bits >> block_size_bits;
7651da177e4SLinus Torvalds 		/* Read the run from device in chunks of block_size bytes. */
7661da177e4SLinus Torvalds 		max_block = block + (rl->length << vol->cluster_size_bits >>
7671da177e4SLinus Torvalds 				block_size_bits);
7681da177e4SLinus Torvalds 		ntfs_debug("max_block = 0x%lx.", max_block);
7691da177e4SLinus Torvalds 		do {
7701da177e4SLinus Torvalds 			ntfs_debug("Reading block = 0x%lx.", block);
7711da177e4SLinus Torvalds 			bh = sb_bread(sb, block);
7721da177e4SLinus Torvalds 			if (!bh) {
7731da177e4SLinus Torvalds 				ntfs_error(sb, "sb_bread() failed. Cannot "
7741da177e4SLinus Torvalds 						"read attribute list.");
7751da177e4SLinus Torvalds 				goto err_out;
7761da177e4SLinus Torvalds 			}
7771da177e4SLinus Torvalds 			if (al + block_size >= al_end)
7781da177e4SLinus Torvalds 				goto do_final;
7791da177e4SLinus Torvalds 			memcpy(al, bh->b_data, block_size);
7801da177e4SLinus Torvalds 			brelse(bh);
7811da177e4SLinus Torvalds 			al += block_size;
7821da177e4SLinus Torvalds 		} while (++block < max_block);
7831da177e4SLinus Torvalds 		rl++;
7841da177e4SLinus Torvalds 	}
7851da177e4SLinus Torvalds 	if (initialized_size < size) {
7861da177e4SLinus Torvalds initialize:
7871da177e4SLinus Torvalds 		memset(al_start + initialized_size, 0, size - initialized_size);
7881da177e4SLinus Torvalds 	}
7891da177e4SLinus Torvalds done:
7901da177e4SLinus Torvalds 	up_read(&runlist->lock);
7911da177e4SLinus Torvalds 	return err;
7921da177e4SLinus Torvalds do_final:
7931da177e4SLinus Torvalds 	if (al < al_end) {
7941da177e4SLinus Torvalds 		/*
7951da177e4SLinus Torvalds 		 * Partial block.
7961da177e4SLinus Torvalds 		 *
7971da177e4SLinus Torvalds 		 * Note: The attribute list can be smaller than its allocation
7981da177e4SLinus Torvalds 		 * by multiple clusters.  This has been encountered by at least
7991da177e4SLinus Torvalds 		 * two people running Windows XP, thus we cannot do any
8001da177e4SLinus Torvalds 		 * truncation sanity checking here. (AIA)
8011da177e4SLinus Torvalds 		 */
8021da177e4SLinus Torvalds 		memcpy(al, bh->b_data, al_end - al);
8031da177e4SLinus Torvalds 		brelse(bh);
8041da177e4SLinus Torvalds 		if (initialized_size < size)
8051da177e4SLinus Torvalds 			goto initialize;
8061da177e4SLinus Torvalds 		goto done;
8071da177e4SLinus Torvalds 	}
8081da177e4SLinus Torvalds 	brelse(bh);
8091da177e4SLinus Torvalds 	/* Real overflow! */
8101da177e4SLinus Torvalds 	ntfs_error(sb, "Attribute list buffer overflow. Read attribute list "
8111da177e4SLinus Torvalds 			"is truncated.");
8121da177e4SLinus Torvalds err_out:
8131da177e4SLinus Torvalds 	err = -EIO;
8141da177e4SLinus Torvalds 	goto done;
8151da177e4SLinus Torvalds }
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds /**
8181da177e4SLinus Torvalds  * ntfs_external_attr_find - find an attribute in the attribute list of an inode
8191da177e4SLinus Torvalds  * @type:	attribute type to find
8201da177e4SLinus Torvalds  * @name:	attribute name to find (optional, i.e. NULL means don't care)
8211da177e4SLinus Torvalds  * @name_len:	attribute name length (only needed if @name present)
8221da177e4SLinus Torvalds  * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
8231da177e4SLinus Torvalds  * @lowest_vcn:	lowest vcn to find (optional, non-resident attributes only)
8241da177e4SLinus Torvalds  * @val:	attribute value to find (optional, resident attributes only)
8251da177e4SLinus Torvalds  * @val_len:	attribute value length
8261da177e4SLinus Torvalds  * @ctx:	search context with mft record and attribute to search from
8271da177e4SLinus Torvalds  *
8281da177e4SLinus Torvalds  * You should not need to call this function directly.  Use ntfs_attr_lookup()
8291da177e4SLinus Torvalds  * instead.
8301da177e4SLinus Torvalds  *
8311da177e4SLinus Torvalds  * Find an attribute by searching the attribute list for the corresponding
8321da177e4SLinus Torvalds  * attribute list entry.  Having found the entry, map the mft record if the
8331da177e4SLinus Torvalds  * attribute is in a different mft record/inode, ntfs_attr_find() the attribute
8341da177e4SLinus Torvalds  * in there and return it.
8351da177e4SLinus Torvalds  *
8361da177e4SLinus Torvalds  * On first search @ctx->ntfs_ino must be the base mft record and @ctx must
8371da177e4SLinus Torvalds  * have been obtained from a call to ntfs_attr_get_search_ctx().  On subsequent
8381da177e4SLinus Torvalds  * calls @ctx->ntfs_ino can be any extent inode, too (@ctx->base_ntfs_ino is
8391da177e4SLinus Torvalds  * then the base inode).
8401da177e4SLinus Torvalds  *
8411da177e4SLinus Torvalds  * After finishing with the attribute/mft record you need to call
8421da177e4SLinus Torvalds  * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
8431da177e4SLinus Torvalds  * mapped inodes, etc).
8441da177e4SLinus Torvalds  *
8451da177e4SLinus Torvalds  * If the attribute is found, ntfs_external_attr_find() returns 0 and
8461da177e4SLinus Torvalds  * @ctx->attr will point to the found attribute.  @ctx->mrec will point to the
8471da177e4SLinus Torvalds  * mft record in which @ctx->attr is located and @ctx->al_entry will point to
8481da177e4SLinus Torvalds  * the attribute list entry for the attribute.
8491da177e4SLinus Torvalds  *
8501da177e4SLinus Torvalds  * If the attribute is not found, ntfs_external_attr_find() returns -ENOENT and
8511da177e4SLinus Torvalds  * @ctx->attr will point to the attribute in the base mft record before which
8521da177e4SLinus Torvalds  * the attribute being searched for would need to be inserted if such an action
8531da177e4SLinus Torvalds  * were to be desired.  @ctx->mrec will point to the mft record in which
8541da177e4SLinus Torvalds  * @ctx->attr is located and @ctx->al_entry will point to the attribute list
8551da177e4SLinus Torvalds  * entry of the attribute before which the attribute being searched for would
8561da177e4SLinus Torvalds  * need to be inserted if such an action were to be desired.
8571da177e4SLinus Torvalds  *
8581da177e4SLinus Torvalds  * Thus to insert the not found attribute, one wants to add the attribute to
8591da177e4SLinus Torvalds  * @ctx->mrec (the base mft record) and if there is not enough space, the
8601da177e4SLinus Torvalds  * attribute should be placed in a newly allocated extent mft record.  The
8611da177e4SLinus Torvalds  * attribute list entry for the inserted attribute should be inserted in the
8621da177e4SLinus Torvalds  * attribute list attribute at @ctx->al_entry.
8631da177e4SLinus Torvalds  *
8641da177e4SLinus Torvalds  * On actual error, ntfs_external_attr_find() returns -EIO.  In this case
8651da177e4SLinus Torvalds  * @ctx->attr is undefined and in particular do not rely on it not changing.
8661da177e4SLinus Torvalds  */
ntfs_external_attr_find(const ATTR_TYPE type,const ntfschar * name,const u32 name_len,const IGNORE_CASE_BOOL ic,const VCN lowest_vcn,const u8 * val,const u32 val_len,ntfs_attr_search_ctx * ctx)8671da177e4SLinus Torvalds static int ntfs_external_attr_find(const ATTR_TYPE type,
8681da177e4SLinus Torvalds 		const ntfschar *name, const u32 name_len,
8691da177e4SLinus Torvalds 		const IGNORE_CASE_BOOL ic, const VCN lowest_vcn,
8701da177e4SLinus Torvalds 		const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx)
8711da177e4SLinus Torvalds {
8721da177e4SLinus Torvalds 	ntfs_inode *base_ni, *ni;
8731da177e4SLinus Torvalds 	ntfs_volume *vol;
8741da177e4SLinus Torvalds 	ATTR_LIST_ENTRY *al_entry, *next_al_entry;
8751da177e4SLinus Torvalds 	u8 *al_start, *al_end;
8761da177e4SLinus Torvalds 	ATTR_RECORD *a;
8771da177e4SLinus Torvalds 	ntfschar *al_name;
8781da177e4SLinus Torvalds 	u32 al_name_len;
8791da177e4SLinus Torvalds 	int err = 0;
8801da177e4SLinus Torvalds 	static const char *es = " Unmount and run chkdsk.";
8811da177e4SLinus Torvalds 
8821da177e4SLinus Torvalds 	ni = ctx->ntfs_ino;
8831da177e4SLinus Torvalds 	base_ni = ctx->base_ntfs_ino;
8841da177e4SLinus Torvalds 	ntfs_debug("Entering for inode 0x%lx, type 0x%x.", ni->mft_no, type);
8851da177e4SLinus Torvalds 	if (!base_ni) {
8861da177e4SLinus Torvalds 		/* First call happens with the base mft record. */
8871da177e4SLinus Torvalds 		base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;
8881da177e4SLinus Torvalds 		ctx->base_mrec = ctx->mrec;
8891da177e4SLinus Torvalds 	}
8901da177e4SLinus Torvalds 	if (ni == base_ni)
8911da177e4SLinus Torvalds 		ctx->base_attr = ctx->attr;
8921da177e4SLinus Torvalds 	if (type == AT_END)
8931da177e4SLinus Torvalds 		goto not_found;
8941da177e4SLinus Torvalds 	vol = base_ni->vol;
8951da177e4SLinus Torvalds 	al_start = base_ni->attr_list;
8961da177e4SLinus Torvalds 	al_end = al_start + base_ni->attr_list_size;
8971da177e4SLinus Torvalds 	if (!ctx->al_entry)
8981da177e4SLinus Torvalds 		ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;
8991da177e4SLinus Torvalds 	/*
9001da177e4SLinus Torvalds 	 * Iterate over entries in attribute list starting at @ctx->al_entry,
901c49c3111SRichard Knutsson 	 * or the entry following that, if @ctx->is_first is 'true'.
9021da177e4SLinus Torvalds 	 */
9031da177e4SLinus Torvalds 	if (ctx->is_first) {
9041da177e4SLinus Torvalds 		al_entry = ctx->al_entry;
905c49c3111SRichard Knutsson 		ctx->is_first = false;
9061da177e4SLinus Torvalds 	} else
9071da177e4SLinus Torvalds 		al_entry = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
9081da177e4SLinus Torvalds 				le16_to_cpu(ctx->al_entry->length));
9091da177e4SLinus Torvalds 	for (;; al_entry = next_al_entry) {
9101da177e4SLinus Torvalds 		/* Out of bounds check. */
9111da177e4SLinus Torvalds 		if ((u8*)al_entry < base_ni->attr_list ||
9121da177e4SLinus Torvalds 				(u8*)al_entry > al_end)
9131da177e4SLinus Torvalds 			break;	/* Inode is corrupt. */
9141da177e4SLinus Torvalds 		ctx->al_entry = al_entry;
9151da177e4SLinus Torvalds 		/* Catch the end of the attribute list. */
9161da177e4SLinus Torvalds 		if ((u8*)al_entry == al_end)
9171da177e4SLinus Torvalds 			goto not_found;
9181da177e4SLinus Torvalds 		if (!al_entry->length)
9191da177e4SLinus Torvalds 			break;
9201da177e4SLinus Torvalds 		if ((u8*)al_entry + 6 > al_end || (u8*)al_entry +
9211da177e4SLinus Torvalds 				le16_to_cpu(al_entry->length) > al_end)
9221da177e4SLinus Torvalds 			break;
9231da177e4SLinus Torvalds 		next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +
9241da177e4SLinus Torvalds 				le16_to_cpu(al_entry->length));
9251da177e4SLinus Torvalds 		if (le32_to_cpu(al_entry->type) > le32_to_cpu(type))
9261da177e4SLinus Torvalds 			goto not_found;
9271da177e4SLinus Torvalds 		if (type != al_entry->type)
9281da177e4SLinus Torvalds 			continue;
9291da177e4SLinus Torvalds 		/*
9301da177e4SLinus Torvalds 		 * If @name is present, compare the two names.  If @name is
9311da177e4SLinus Torvalds 		 * missing, assume we want an unnamed attribute.
9321da177e4SLinus Torvalds 		 */
9331da177e4SLinus Torvalds 		al_name_len = al_entry->name_length;
9341da177e4SLinus Torvalds 		al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset);
9351da177e4SLinus Torvalds 		if (!name) {
9361da177e4SLinus Torvalds 			if (al_name_len)
9371da177e4SLinus Torvalds 				goto not_found;
9381da177e4SLinus Torvalds 		} else if (!ntfs_are_names_equal(al_name, al_name_len, name,
9391da177e4SLinus Torvalds 				name_len, ic, vol->upcase, vol->upcase_len)) {
9401da177e4SLinus Torvalds 			register int rc;
9411da177e4SLinus Torvalds 
9421da177e4SLinus Torvalds 			rc = ntfs_collate_names(name, name_len, al_name,
9431da177e4SLinus Torvalds 					al_name_len, 1, IGNORE_CASE,
9441da177e4SLinus Torvalds 					vol->upcase, vol->upcase_len);
9451da177e4SLinus Torvalds 			/*
9461da177e4SLinus Torvalds 			 * If @name collates before al_name, there is no
9471da177e4SLinus Torvalds 			 * matching attribute.
9481da177e4SLinus Torvalds 			 */
9491da177e4SLinus Torvalds 			if (rc == -1)
9501da177e4SLinus Torvalds 				goto not_found;
9511da177e4SLinus Torvalds 			/* If the strings are not equal, continue search. */
9521da177e4SLinus Torvalds 			if (rc)
9531da177e4SLinus Torvalds 				continue;
9541da177e4SLinus Torvalds 			/*
9551da177e4SLinus Torvalds 			 * FIXME: Reverse engineering showed 0, IGNORE_CASE but
9561da177e4SLinus Torvalds 			 * that is inconsistent with ntfs_attr_find().  The
9571da177e4SLinus Torvalds 			 * subsequent rc checks were also different.  Perhaps I
9581da177e4SLinus Torvalds 			 * made a mistake in one of the two.  Need to recheck
9591da177e4SLinus Torvalds 			 * which is correct or at least see what is going on...
9601da177e4SLinus Torvalds 			 * (AIA)
9611da177e4SLinus Torvalds 			 */
9621da177e4SLinus Torvalds 			rc = ntfs_collate_names(name, name_len, al_name,
9631da177e4SLinus Torvalds 					al_name_len, 1, CASE_SENSITIVE,
9641da177e4SLinus Torvalds 					vol->upcase, vol->upcase_len);
9651da177e4SLinus Torvalds 			if (rc == -1)
9661da177e4SLinus Torvalds 				goto not_found;
9671da177e4SLinus Torvalds 			if (rc)
9681da177e4SLinus Torvalds 				continue;
9691da177e4SLinus Torvalds 		}
9701da177e4SLinus Torvalds 		/*
9711da177e4SLinus Torvalds 		 * The names match or @name not present and attribute is
9721da177e4SLinus Torvalds 		 * unnamed.  Now check @lowest_vcn.  Continue search if the
9731da177e4SLinus Torvalds 		 * next attribute list entry still fits @lowest_vcn.  Otherwise
9741da177e4SLinus Torvalds 		 * we have reached the right one or the search has failed.
9751da177e4SLinus Torvalds 		 */
9761da177e4SLinus Torvalds 		if (lowest_vcn && (u8*)next_al_entry >= al_start	    &&
9771da177e4SLinus Torvalds 				(u8*)next_al_entry + 6 < al_end		    &&
9781da177e4SLinus Torvalds 				(u8*)next_al_entry + le16_to_cpu(
9791da177e4SLinus Torvalds 					next_al_entry->length) <= al_end    &&
9801da177e4SLinus Torvalds 				sle64_to_cpu(next_al_entry->lowest_vcn) <=
9811da177e4SLinus Torvalds 					lowest_vcn			    &&
9821da177e4SLinus Torvalds 				next_al_entry->type == al_entry->type	    &&
9831da177e4SLinus Torvalds 				next_al_entry->name_length == al_name_len   &&
9841da177e4SLinus Torvalds 				ntfs_are_names_equal((ntfschar*)((u8*)
9851da177e4SLinus Torvalds 					next_al_entry +
9861da177e4SLinus Torvalds 					next_al_entry->name_offset),
9871da177e4SLinus Torvalds 					next_al_entry->name_length,
9881da177e4SLinus Torvalds 					al_name, al_name_len, CASE_SENSITIVE,
9891da177e4SLinus Torvalds 					vol->upcase, vol->upcase_len))
9901da177e4SLinus Torvalds 			continue;
9911da177e4SLinus Torvalds 		if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {
9921da177e4SLinus Torvalds 			if (MSEQNO_LE(al_entry->mft_reference) != ni->seq_no) {
9931da177e4SLinus Torvalds 				ntfs_error(vol->sb, "Found stale mft "
9941da177e4SLinus Torvalds 						"reference in attribute list "
9951da177e4SLinus Torvalds 						"of base inode 0x%lx.%s",
9961da177e4SLinus Torvalds 						base_ni->mft_no, es);
9971da177e4SLinus Torvalds 				err = -EIO;
9981da177e4SLinus Torvalds 				break;
9991da177e4SLinus Torvalds 			}
10001da177e4SLinus Torvalds 		} else { /* Mft references do not match. */
10011da177e4SLinus Torvalds 			/* If there is a mapped record unmap it first. */
10021da177e4SLinus Torvalds 			if (ni != base_ni)
10031da177e4SLinus Torvalds 				unmap_extent_mft_record(ni);
10041da177e4SLinus Torvalds 			/* Do we want the base record back? */
10051da177e4SLinus Torvalds 			if (MREF_LE(al_entry->mft_reference) ==
10061da177e4SLinus Torvalds 					base_ni->mft_no) {
10071da177e4SLinus Torvalds 				ni = ctx->ntfs_ino = base_ni;
10081da177e4SLinus Torvalds 				ctx->mrec = ctx->base_mrec;
10091da177e4SLinus Torvalds 			} else {
10101da177e4SLinus Torvalds 				/* We want an extent record. */
10111da177e4SLinus Torvalds 				ctx->mrec = map_extent_mft_record(base_ni,
10121da177e4SLinus Torvalds 						le64_to_cpu(
10131da177e4SLinus Torvalds 						al_entry->mft_reference), &ni);
10141da177e4SLinus Torvalds 				if (IS_ERR(ctx->mrec)) {
10151da177e4SLinus Torvalds 					ntfs_error(vol->sb, "Failed to map "
10161da177e4SLinus Torvalds 							"extent mft record "
10171da177e4SLinus Torvalds 							"0x%lx of base inode "
10181da177e4SLinus Torvalds 							"0x%lx.%s",
10191da177e4SLinus Torvalds 							MREF_LE(al_entry->
10201da177e4SLinus Torvalds 							mft_reference),
10211da177e4SLinus Torvalds 							base_ni->mft_no, es);
10221da177e4SLinus Torvalds 					err = PTR_ERR(ctx->mrec);
10231da177e4SLinus Torvalds 					if (err == -ENOENT)
10241da177e4SLinus Torvalds 						err = -EIO;
10251da177e4SLinus Torvalds 					/* Cause @ctx to be sanitized below. */
10261da177e4SLinus Torvalds 					ni = NULL;
10271da177e4SLinus Torvalds 					break;
10281da177e4SLinus Torvalds 				}
10291da177e4SLinus Torvalds 				ctx->ntfs_ino = ni;
10301da177e4SLinus Torvalds 			}
10311da177e4SLinus Torvalds 			ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
10321da177e4SLinus Torvalds 					le16_to_cpu(ctx->mrec->attrs_offset));
10331da177e4SLinus Torvalds 		}
10341da177e4SLinus Torvalds 		/*
10351da177e4SLinus Torvalds 		 * ctx->vfs_ino, ctx->mrec, and ctx->attr now point to the
10361da177e4SLinus Torvalds 		 * mft record containing the attribute represented by the
10371da177e4SLinus Torvalds 		 * current al_entry.
10381da177e4SLinus Torvalds 		 */
10391da177e4SLinus Torvalds 		/*
10401da177e4SLinus Torvalds 		 * We could call into ntfs_attr_find() to find the right
10411da177e4SLinus Torvalds 		 * attribute in this mft record but this would be less
10421da177e4SLinus Torvalds 		 * efficient and not quite accurate as ntfs_attr_find() ignores
10431da177e4SLinus Torvalds 		 * the attribute instance numbers for example which become
10441da177e4SLinus Torvalds 		 * important when one plays with attribute lists.  Also,
10451da177e4SLinus Torvalds 		 * because a proper match has been found in the attribute list
10461da177e4SLinus Torvalds 		 * entry above, the comparison can now be optimized.  So it is
10471da177e4SLinus Torvalds 		 * worth re-implementing a simplified ntfs_attr_find() here.
10481da177e4SLinus Torvalds 		 */
10491da177e4SLinus Torvalds 		a = ctx->attr;
10501da177e4SLinus Torvalds 		/*
10511da177e4SLinus Torvalds 		 * Use a manual loop so we can still use break and continue
10521da177e4SLinus Torvalds 		 * with the same meanings as above.
10531da177e4SLinus Torvalds 		 */
10541da177e4SLinus Torvalds do_next_attr_loop:
10551da177e4SLinus Torvalds 		if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec +
10561da177e4SLinus Torvalds 				le32_to_cpu(ctx->mrec->bytes_allocated))
10571da177e4SLinus Torvalds 			break;
10581da177e4SLinus Torvalds 		if (a->type == AT_END)
10593ccc7384SAnton Altaparmakov 			break;
10601da177e4SLinus Torvalds 		if (!a->length)
10611da177e4SLinus Torvalds 			break;
10621da177e4SLinus Torvalds 		if (al_entry->instance != a->instance)
10631da177e4SLinus Torvalds 			goto do_next_attr;
10641da177e4SLinus Torvalds 		/*
10651da177e4SLinus Torvalds 		 * If the type and/or the name are mismatched between the
10661da177e4SLinus Torvalds 		 * attribute list entry and the attribute record, there is
10671da177e4SLinus Torvalds 		 * corruption so we break and return error EIO.
10681da177e4SLinus Torvalds 		 */
10691da177e4SLinus Torvalds 		if (al_entry->type != a->type)
10701da177e4SLinus Torvalds 			break;
10711da177e4SLinus Torvalds 		if (!ntfs_are_names_equal((ntfschar*)((u8*)a +
10721da177e4SLinus Torvalds 				le16_to_cpu(a->name_offset)), a->name_length,
10731da177e4SLinus Torvalds 				al_name, al_name_len, CASE_SENSITIVE,
10741da177e4SLinus Torvalds 				vol->upcase, vol->upcase_len))
10751da177e4SLinus Torvalds 			break;
10761da177e4SLinus Torvalds 		ctx->attr = a;
10771da177e4SLinus Torvalds 		/*
10781da177e4SLinus Torvalds 		 * If no @val specified or @val specified and it matches, we
10791da177e4SLinus Torvalds 		 * have found it!
10801da177e4SLinus Torvalds 		 */
10811da177e4SLinus Torvalds 		if (!val || (!a->non_resident && le32_to_cpu(
10821da177e4SLinus Torvalds 				a->data.resident.value_length) == val_len &&
10831da177e4SLinus Torvalds 				!memcmp((u8*)a +
10841da177e4SLinus Torvalds 				le16_to_cpu(a->data.resident.value_offset),
10851da177e4SLinus Torvalds 				val, val_len))) {
10861da177e4SLinus Torvalds 			ntfs_debug("Done, found.");
10871da177e4SLinus Torvalds 			return 0;
10881da177e4SLinus Torvalds 		}
10891da177e4SLinus Torvalds do_next_attr:
10901da177e4SLinus Torvalds 		/* Proceed to the next attribute in the current mft record. */
10911da177e4SLinus Torvalds 		a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length));
10921da177e4SLinus Torvalds 		goto do_next_attr_loop;
10931da177e4SLinus Torvalds 	}
10941da177e4SLinus Torvalds 	if (!err) {
10951da177e4SLinus Torvalds 		ntfs_error(vol->sb, "Base inode 0x%lx contains corrupt "
10961da177e4SLinus Torvalds 				"attribute list attribute.%s", base_ni->mft_no,
10971da177e4SLinus Torvalds 				es);
10981da177e4SLinus Torvalds 		err = -EIO;
10991da177e4SLinus Torvalds 	}
11001da177e4SLinus Torvalds 	if (ni != base_ni) {
11011da177e4SLinus Torvalds 		if (ni)
11021da177e4SLinus Torvalds 			unmap_extent_mft_record(ni);
11031da177e4SLinus Torvalds 		ctx->ntfs_ino = base_ni;
11041da177e4SLinus Torvalds 		ctx->mrec = ctx->base_mrec;
11051da177e4SLinus Torvalds 		ctx->attr = ctx->base_attr;
11061da177e4SLinus Torvalds 	}
11071da177e4SLinus Torvalds 	if (err != -ENOMEM)
11081da177e4SLinus Torvalds 		NVolSetErrors(vol);
11091da177e4SLinus Torvalds 	return err;
11101da177e4SLinus Torvalds not_found:
11111da177e4SLinus Torvalds 	/*
11121da177e4SLinus Torvalds 	 * If we were looking for AT_END, we reset the search context @ctx and
11131da177e4SLinus Torvalds 	 * use ntfs_attr_find() to seek to the end of the base mft record.
11141da177e4SLinus Torvalds 	 */
11151da177e4SLinus Torvalds 	if (type == AT_END) {
11161da177e4SLinus Torvalds 		ntfs_attr_reinit_search_ctx(ctx);
11171da177e4SLinus Torvalds 		return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len,
11181da177e4SLinus Torvalds 				ctx);
11191da177e4SLinus Torvalds 	}
11201da177e4SLinus Torvalds 	/*
11211da177e4SLinus Torvalds 	 * The attribute was not found.  Before we return, we want to ensure
11221da177e4SLinus Torvalds 	 * @ctx->mrec and @ctx->attr indicate the position at which the
11231da177e4SLinus Torvalds 	 * attribute should be inserted in the base mft record.  Since we also
11241da177e4SLinus Torvalds 	 * want to preserve @ctx->al_entry we cannot reinitialize the search
11251da177e4SLinus Torvalds 	 * context using ntfs_attr_reinit_search_ctx() as this would set
11261da177e4SLinus Torvalds 	 * @ctx->al_entry to NULL.  Thus we do the necessary bits manually (see
11271da177e4SLinus Torvalds 	 * ntfs_attr_init_search_ctx() below).  Note, we _only_ preserve
11281da177e4SLinus Torvalds 	 * @ctx->al_entry as the remaining fields (base_*) are identical to
11291da177e4SLinus Torvalds 	 * their non base_ counterparts and we cannot set @ctx->base_attr
11301da177e4SLinus Torvalds 	 * correctly yet as we do not know what @ctx->attr will be set to by
11311da177e4SLinus Torvalds 	 * the call to ntfs_attr_find() below.
11321da177e4SLinus Torvalds 	 */
11331da177e4SLinus Torvalds 	if (ni != base_ni)
11341da177e4SLinus Torvalds 		unmap_extent_mft_record(ni);
11351da177e4SLinus Torvalds 	ctx->mrec = ctx->base_mrec;
11361da177e4SLinus Torvalds 	ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
11371da177e4SLinus Torvalds 			le16_to_cpu(ctx->mrec->attrs_offset));
1138c49c3111SRichard Knutsson 	ctx->is_first = true;
11391da177e4SLinus Torvalds 	ctx->ntfs_ino = base_ni;
11401da177e4SLinus Torvalds 	ctx->base_ntfs_ino = NULL;
11411da177e4SLinus Torvalds 	ctx->base_mrec = NULL;
11421da177e4SLinus Torvalds 	ctx->base_attr = NULL;
11431da177e4SLinus Torvalds 	/*
11441da177e4SLinus Torvalds 	 * In case there are multiple matches in the base mft record, need to
11451da177e4SLinus Torvalds 	 * keep enumerating until we get an attribute not found response (or
11461da177e4SLinus Torvalds 	 * another error), otherwise we would keep returning the same attribute
11471da177e4SLinus Torvalds 	 * over and over again and all programs using us for enumeration would
11481da177e4SLinus Torvalds 	 * lock up in a tight loop.
11491da177e4SLinus Torvalds 	 */
11501da177e4SLinus Torvalds 	do {
11511da177e4SLinus Torvalds 		err = ntfs_attr_find(type, name, name_len, ic, val, val_len,
11521da177e4SLinus Torvalds 				ctx);
11531da177e4SLinus Torvalds 	} while (!err);
11541da177e4SLinus Torvalds 	ntfs_debug("Done, not found.");
11551da177e4SLinus Torvalds 	return err;
11561da177e4SLinus Torvalds }
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds /**
11591da177e4SLinus Torvalds  * ntfs_attr_lookup - find an attribute in an ntfs inode
11601da177e4SLinus Torvalds  * @type:	attribute type to find
11611da177e4SLinus Torvalds  * @name:	attribute name to find (optional, i.e. NULL means don't care)
11621da177e4SLinus Torvalds  * @name_len:	attribute name length (only needed if @name present)
11631da177e4SLinus Torvalds  * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
11641da177e4SLinus Torvalds  * @lowest_vcn:	lowest vcn to find (optional, non-resident attributes only)
11651da177e4SLinus Torvalds  * @val:	attribute value to find (optional, resident attributes only)
11661da177e4SLinus Torvalds  * @val_len:	attribute value length
11671da177e4SLinus Torvalds  * @ctx:	search context with mft record and attribute to search from
11681da177e4SLinus Torvalds  *
11691da177e4SLinus Torvalds  * Find an attribute in an ntfs inode.  On first search @ctx->ntfs_ino must
11701da177e4SLinus Torvalds  * be the base mft record and @ctx must have been obtained from a call to
11711da177e4SLinus Torvalds  * ntfs_attr_get_search_ctx().
11721da177e4SLinus Torvalds  *
11731da177e4SLinus Torvalds  * This function transparently handles attribute lists and @ctx is used to
11741da177e4SLinus Torvalds  * continue searches where they were left off at.
11751da177e4SLinus Torvalds  *
11761da177e4SLinus Torvalds  * After finishing with the attribute/mft record you need to call
11771da177e4SLinus Torvalds  * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
11781da177e4SLinus Torvalds  * mapped inodes, etc).
11791da177e4SLinus Torvalds  *
11801da177e4SLinus Torvalds  * Return 0 if the search was successful and -errno if not.
11811da177e4SLinus Torvalds  *
11821da177e4SLinus Torvalds  * When 0, @ctx->attr is the found attribute and it is in mft record
11831da177e4SLinus Torvalds  * @ctx->mrec.  If an attribute list attribute is present, @ctx->al_entry is
11841da177e4SLinus Torvalds  * the attribute list entry of the found attribute.
11851da177e4SLinus Torvalds  *
11861da177e4SLinus Torvalds  * When -ENOENT, @ctx->attr is the attribute which collates just after the
11871da177e4SLinus Torvalds  * attribute being searched for, i.e. if one wants to add the attribute to the
11881da177e4SLinus Torvalds  * mft record this is the correct place to insert it into.  If an attribute
11891da177e4SLinus Torvalds  * list attribute is present, @ctx->al_entry is the attribute list entry which
11901da177e4SLinus Torvalds  * collates just after the attribute list entry of the attribute being searched
11911da177e4SLinus Torvalds  * for, i.e. if one wants to add the attribute to the mft record this is the
11921da177e4SLinus Torvalds  * correct place to insert its attribute list entry into.
11931da177e4SLinus Torvalds  *
119425985edcSLucas De Marchi  * When -errno != -ENOENT, an error occurred during the lookup.  @ctx->attr is
11951da177e4SLinus Torvalds  * then undefined and in particular you should not rely on it not changing.
11961da177e4SLinus Torvalds  */
ntfs_attr_lookup(const ATTR_TYPE type,const ntfschar * name,const u32 name_len,const IGNORE_CASE_BOOL ic,const VCN lowest_vcn,const u8 * val,const u32 val_len,ntfs_attr_search_ctx * ctx)11971da177e4SLinus Torvalds int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
11981da177e4SLinus Torvalds 		const u32 name_len, const IGNORE_CASE_BOOL ic,
11991da177e4SLinus Torvalds 		const VCN lowest_vcn, const u8 *val, const u32 val_len,
12001da177e4SLinus Torvalds 		ntfs_attr_search_ctx *ctx)
12011da177e4SLinus Torvalds {
12021da177e4SLinus Torvalds 	ntfs_inode *base_ni;
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds 	ntfs_debug("Entering.");
120569b41e3cSAnton Altaparmakov 	BUG_ON(IS_ERR(ctx->mrec));
12061da177e4SLinus Torvalds 	if (ctx->base_ntfs_ino)
12071da177e4SLinus Torvalds 		base_ni = ctx->base_ntfs_ino;
12081da177e4SLinus Torvalds 	else
12091da177e4SLinus Torvalds 		base_ni = ctx->ntfs_ino;
12101da177e4SLinus Torvalds 	/* Sanity check, just for debugging really. */
12111da177e4SLinus Torvalds 	BUG_ON(!base_ni);
12121da177e4SLinus Torvalds 	if (!NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST)
12131da177e4SLinus Torvalds 		return ntfs_attr_find(type, name, name_len, ic, val, val_len,
12141da177e4SLinus Torvalds 				ctx);
12151da177e4SLinus Torvalds 	return ntfs_external_attr_find(type, name, name_len, ic, lowest_vcn,
12161da177e4SLinus Torvalds 			val, val_len, ctx);
12171da177e4SLinus Torvalds }
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds /**
12201da177e4SLinus Torvalds  * ntfs_attr_init_search_ctx - initialize an attribute search context
12211da177e4SLinus Torvalds  * @ctx:	attribute search context to initialize
12221da177e4SLinus Torvalds  * @ni:		ntfs inode with which to initialize the search context
12231da177e4SLinus Torvalds  * @mrec:	mft record with which to initialize the search context
12241da177e4SLinus Torvalds  *
12251da177e4SLinus Torvalds  * Initialize the attribute search context @ctx with @ni and @mrec.
12261da177e4SLinus Torvalds  */
ntfs_attr_init_search_ctx(ntfs_attr_search_ctx * ctx,ntfs_inode * ni,MFT_RECORD * mrec)12271da177e4SLinus Torvalds static inline void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx,
12281da177e4SLinus Torvalds 		ntfs_inode *ni, MFT_RECORD *mrec)
12291da177e4SLinus Torvalds {
1230442d207eSAnton Altaparmakov 	*ctx = (ntfs_attr_search_ctx) {
1231442d207eSAnton Altaparmakov 		.mrec = mrec,
12321da177e4SLinus Torvalds 		/* Sanity checks are performed elsewhere. */
1233442d207eSAnton Altaparmakov 		.attr = (ATTR_RECORD*)((u8*)mrec +
1234442d207eSAnton Altaparmakov 				le16_to_cpu(mrec->attrs_offset)),
1235c49c3111SRichard Knutsson 		.is_first = true,
1236442d207eSAnton Altaparmakov 		.ntfs_ino = ni,
1237442d207eSAnton Altaparmakov 	};
12381da177e4SLinus Torvalds }
12391da177e4SLinus Torvalds 
12401da177e4SLinus Torvalds /**
12411da177e4SLinus Torvalds  * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context
12421da177e4SLinus Torvalds  * @ctx:	attribute search context to reinitialize
12431da177e4SLinus Torvalds  *
12441da177e4SLinus Torvalds  * Reinitialize the attribute search context @ctx, unmapping an associated
12451da177e4SLinus Torvalds  * extent mft record if present, and initialize the search context again.
12461da177e4SLinus Torvalds  *
12471da177e4SLinus Torvalds  * This is used when a search for a new attribute is being started to reset
12481da177e4SLinus Torvalds  * the search context to the beginning.
12491da177e4SLinus Torvalds  */
ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx * ctx)12501da177e4SLinus Torvalds void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx)
12511da177e4SLinus Torvalds {
12521da177e4SLinus Torvalds 	if (likely(!ctx->base_ntfs_ino)) {
12531da177e4SLinus Torvalds 		/* No attribute list. */
1254c49c3111SRichard Knutsson 		ctx->is_first = true;
12551da177e4SLinus Torvalds 		/* Sanity checks are performed elsewhere. */
12561da177e4SLinus Torvalds 		ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
12571da177e4SLinus Torvalds 				le16_to_cpu(ctx->mrec->attrs_offset));
12581da177e4SLinus Torvalds 		/*
12591da177e4SLinus Torvalds 		 * This needs resetting due to ntfs_external_attr_find() which
12601da177e4SLinus Torvalds 		 * can leave it set despite having zeroed ctx->base_ntfs_ino.
12611da177e4SLinus Torvalds 		 */
12621da177e4SLinus Torvalds 		ctx->al_entry = NULL;
12631da177e4SLinus Torvalds 		return;
12641da177e4SLinus Torvalds 	} /* Attribute list. */
12651da177e4SLinus Torvalds 	if (ctx->ntfs_ino != ctx->base_ntfs_ino)
12661da177e4SLinus Torvalds 		unmap_extent_mft_record(ctx->ntfs_ino);
12671da177e4SLinus Torvalds 	ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
12681da177e4SLinus Torvalds 	return;
12691da177e4SLinus Torvalds }
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds /**
12721da177e4SLinus Torvalds  * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context
12731da177e4SLinus Torvalds  * @ni:		ntfs inode with which to initialize the search context
12741da177e4SLinus Torvalds  * @mrec:	mft record with which to initialize the search context
12751da177e4SLinus Torvalds  *
12761da177e4SLinus Torvalds  * Allocate a new attribute search context, initialize it with @ni and @mrec,
12771da177e4SLinus Torvalds  * and return it. Return NULL if allocation failed.
12781da177e4SLinus Torvalds  */
ntfs_attr_get_search_ctx(ntfs_inode * ni,MFT_RECORD * mrec)12791da177e4SLinus Torvalds ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
12801da177e4SLinus Torvalds {
12811da177e4SLinus Torvalds 	ntfs_attr_search_ctx *ctx;
12821da177e4SLinus Torvalds 
1283e6b4f8daSChristoph Lameter 	ctx = kmem_cache_alloc(ntfs_attr_ctx_cache, GFP_NOFS);
12841da177e4SLinus Torvalds 	if (ctx)
12851da177e4SLinus Torvalds 		ntfs_attr_init_search_ctx(ctx, ni, mrec);
12861da177e4SLinus Torvalds 	return ctx;
12871da177e4SLinus Torvalds }
12881da177e4SLinus Torvalds 
12891da177e4SLinus Torvalds /**
12901da177e4SLinus Torvalds  * ntfs_attr_put_search_ctx - release an attribute search context
12911da177e4SLinus Torvalds  * @ctx:	attribute search context to free
12921da177e4SLinus Torvalds  *
12931da177e4SLinus Torvalds  * Release the attribute search context @ctx, unmapping an associated extent
12941da177e4SLinus Torvalds  * mft record if present.
12951da177e4SLinus Torvalds  */
ntfs_attr_put_search_ctx(ntfs_attr_search_ctx * ctx)12961da177e4SLinus Torvalds void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx)
12971da177e4SLinus Torvalds {
12981da177e4SLinus Torvalds 	if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino)
12991da177e4SLinus Torvalds 		unmap_extent_mft_record(ctx->ntfs_ino);
13001da177e4SLinus Torvalds 	kmem_cache_free(ntfs_attr_ctx_cache, ctx);
13011da177e4SLinus Torvalds 	return;
13021da177e4SLinus Torvalds }
13031da177e4SLinus Torvalds 
130453d59aadSAnton Altaparmakov #ifdef NTFS_RW
130553d59aadSAnton Altaparmakov 
13061da177e4SLinus Torvalds /**
13071da177e4SLinus Torvalds  * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file
13081da177e4SLinus Torvalds  * @vol:	ntfs volume to which the attribute belongs
13091da177e4SLinus Torvalds  * @type:	attribute type which to find
13101da177e4SLinus Torvalds  *
13111da177e4SLinus Torvalds  * Search for the attribute definition record corresponding to the attribute
13121da177e4SLinus Torvalds  * @type in the $AttrDef system file.
13131da177e4SLinus Torvalds  *
13141da177e4SLinus Torvalds  * Return the attribute type definition record if found and NULL if not found.
13151da177e4SLinus Torvalds  */
ntfs_attr_find_in_attrdef(const ntfs_volume * vol,const ATTR_TYPE type)13161da177e4SLinus Torvalds static ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
13171da177e4SLinus Torvalds 		const ATTR_TYPE type)
13181da177e4SLinus Torvalds {
13191da177e4SLinus Torvalds 	ATTR_DEF *ad;
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds 	BUG_ON(!vol->attrdef);
13221da177e4SLinus Torvalds 	BUG_ON(!type);
13231da177e4SLinus Torvalds 	for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef <
13241da177e4SLinus Torvalds 			vol->attrdef_size && ad->type; ++ad) {
13251da177e4SLinus Torvalds 		/* We have not found it yet, carry on searching. */
13261da177e4SLinus Torvalds 		if (likely(le32_to_cpu(ad->type) < le32_to_cpu(type)))
13271da177e4SLinus Torvalds 			continue;
13281da177e4SLinus Torvalds 		/* We found the attribute; return it. */
13291da177e4SLinus Torvalds 		if (likely(ad->type == type))
13301da177e4SLinus Torvalds 			return ad;
13311da177e4SLinus Torvalds 		/* We have gone too far already.  No point in continuing. */
13321da177e4SLinus Torvalds 		break;
13331da177e4SLinus Torvalds 	}
13341da177e4SLinus Torvalds 	/* Attribute not found. */
13351da177e4SLinus Torvalds 	ntfs_debug("Attribute type 0x%x not found in $AttrDef.",
13361da177e4SLinus Torvalds 			le32_to_cpu(type));
13371da177e4SLinus Torvalds 	return NULL;
13381da177e4SLinus Torvalds }
13391da177e4SLinus Torvalds 
13401da177e4SLinus Torvalds /**
13411da177e4SLinus Torvalds  * ntfs_attr_size_bounds_check - check a size of an attribute type for validity
13421da177e4SLinus Torvalds  * @vol:	ntfs volume to which the attribute belongs
13431da177e4SLinus Torvalds  * @type:	attribute type which to check
13441da177e4SLinus Torvalds  * @size:	size which to check
13451da177e4SLinus Torvalds  *
13461da177e4SLinus Torvalds  * Check whether the @size in bytes is valid for an attribute of @type on the
13471da177e4SLinus Torvalds  * ntfs volume @vol.  This information is obtained from $AttrDef system file.
13481da177e4SLinus Torvalds  *
13491da177e4SLinus Torvalds  * Return 0 if valid, -ERANGE if not valid, or -ENOENT if the attribute is not
13501da177e4SLinus Torvalds  * listed in $AttrDef.
13511da177e4SLinus Torvalds  */
ntfs_attr_size_bounds_check(const ntfs_volume * vol,const ATTR_TYPE type,const s64 size)13521da177e4SLinus Torvalds int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPE type,
13531da177e4SLinus Torvalds 		const s64 size)
13541da177e4SLinus Torvalds {
13551da177e4SLinus Torvalds 	ATTR_DEF *ad;
13561da177e4SLinus Torvalds 
13571da177e4SLinus Torvalds 	BUG_ON(size < 0);
13581da177e4SLinus Torvalds 	/*
13591da177e4SLinus Torvalds 	 * $ATTRIBUTE_LIST has a maximum size of 256kiB, but this is not
13601da177e4SLinus Torvalds 	 * listed in $AttrDef.
13611da177e4SLinus Torvalds 	 */
13621da177e4SLinus Torvalds 	if (unlikely(type == AT_ATTRIBUTE_LIST && size > 256 * 1024))
13631da177e4SLinus Torvalds 		return -ERANGE;
13641da177e4SLinus Torvalds 	/* Get the $AttrDef entry for the attribute @type. */
13651da177e4SLinus Torvalds 	ad = ntfs_attr_find_in_attrdef(vol, type);
13661da177e4SLinus Torvalds 	if (unlikely(!ad))
13671da177e4SLinus Torvalds 		return -ENOENT;
13681da177e4SLinus Torvalds 	/* Do the bounds check. */
13691da177e4SLinus Torvalds 	if (((sle64_to_cpu(ad->min_size) > 0) &&
13701da177e4SLinus Torvalds 			size < sle64_to_cpu(ad->min_size)) ||
13711da177e4SLinus Torvalds 			((sle64_to_cpu(ad->max_size) > 0) && size >
13721da177e4SLinus Torvalds 			sle64_to_cpu(ad->max_size)))
13731da177e4SLinus Torvalds 		return -ERANGE;
13741da177e4SLinus Torvalds 	return 0;
13751da177e4SLinus Torvalds }
13761da177e4SLinus Torvalds 
13771da177e4SLinus Torvalds /**
13781da177e4SLinus Torvalds  * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident
13791da177e4SLinus Torvalds  * @vol:	ntfs volume to which the attribute belongs
13801da177e4SLinus Torvalds  * @type:	attribute type which to check
13811da177e4SLinus Torvalds  *
13821da177e4SLinus Torvalds  * Check whether the attribute of @type on the ntfs volume @vol is allowed to
13831da177e4SLinus Torvalds  * be non-resident.  This information is obtained from $AttrDef system file.
13841da177e4SLinus Torvalds  *
1385bb3cf335SAnton Altaparmakov  * Return 0 if the attribute is allowed to be non-resident, -EPERM if not, and
13861da177e4SLinus Torvalds  * -ENOENT if the attribute is not listed in $AttrDef.
13871da177e4SLinus Torvalds  */
ntfs_attr_can_be_non_resident(const ntfs_volume * vol,const ATTR_TYPE type)13881da177e4SLinus Torvalds int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPE type)
13891da177e4SLinus Torvalds {
13901da177e4SLinus Torvalds 	ATTR_DEF *ad;
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	/* Find the attribute definition record in $AttrDef. */
13931da177e4SLinus Torvalds 	ad = ntfs_attr_find_in_attrdef(vol, type);
13941da177e4SLinus Torvalds 	if (unlikely(!ad))
13951da177e4SLinus Torvalds 		return -ENOENT;
13961da177e4SLinus Torvalds 	/* Check the flags and return the result. */
1397bb3cf335SAnton Altaparmakov 	if (ad->flags & ATTR_DEF_RESIDENT)
13981da177e4SLinus Torvalds 		return -EPERM;
1399bb3cf335SAnton Altaparmakov 	return 0;
14001da177e4SLinus Torvalds }
14011da177e4SLinus Torvalds 
14021da177e4SLinus Torvalds /**
14031da177e4SLinus Torvalds  * ntfs_attr_can_be_resident - check if an attribute can be resident
14041da177e4SLinus Torvalds  * @vol:	ntfs volume to which the attribute belongs
14051da177e4SLinus Torvalds  * @type:	attribute type which to check
14061da177e4SLinus Torvalds  *
14071da177e4SLinus Torvalds  * Check whether the attribute of @type on the ntfs volume @vol is allowed to
14081da177e4SLinus Torvalds  * be resident.  This information is derived from our ntfs knowledge and may
14091da177e4SLinus Torvalds  * not be completely accurate, especially when user defined attributes are
14101da177e4SLinus Torvalds  * present.  Basically we allow everything to be resident except for index
14111da177e4SLinus Torvalds  * allocation and $EA attributes.
14121da177e4SLinus Torvalds  *
14131da177e4SLinus Torvalds  * Return 0 if the attribute is allowed to be non-resident and -EPERM if not.
14141da177e4SLinus Torvalds  *
14151da177e4SLinus Torvalds  * Warning: In the system file $MFT the attribute $Bitmap must be non-resident
14161da177e4SLinus Torvalds  *	    otherwise windows will not boot (blue screen of death)!  We cannot
14171da177e4SLinus Torvalds  *	    check for this here as we do not know which inode's $Bitmap is
14181da177e4SLinus Torvalds  *	    being asked about so the caller needs to special case this.
14191da177e4SLinus Torvalds  */
ntfs_attr_can_be_resident(const ntfs_volume * vol,const ATTR_TYPE type)14201da177e4SLinus Torvalds int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type)
14211da177e4SLinus Torvalds {
14227d0ffdb2SAnton Altaparmakov 	if (type == AT_INDEX_ALLOCATION)
14231da177e4SLinus Torvalds 		return -EPERM;
1424bb3cf335SAnton Altaparmakov 	return 0;
14251da177e4SLinus Torvalds }
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds /**
14281da177e4SLinus Torvalds  * ntfs_attr_record_resize - resize an attribute record
14291da177e4SLinus Torvalds  * @m:		mft record containing attribute record
14301da177e4SLinus Torvalds  * @a:		attribute record to resize
14311da177e4SLinus Torvalds  * @new_size:	new size in bytes to which to resize the attribute record @a
14321da177e4SLinus Torvalds  *
14331da177e4SLinus Torvalds  * Resize the attribute record @a, i.e. the resident part of the attribute, in
14341da177e4SLinus Torvalds  * the mft record @m to @new_size bytes.
14351da177e4SLinus Torvalds  *
14361da177e4SLinus Torvalds  * Return 0 on success and -errno on error.  The following error codes are
14371da177e4SLinus Torvalds  * defined:
14381da177e4SLinus Torvalds  *	-ENOSPC	- Not enough space in the mft record @m to perform the resize.
14391da177e4SLinus Torvalds  *
14401da177e4SLinus Torvalds  * Note: On error, no modifications have been performed whatsoever.
14411da177e4SLinus Torvalds  *
14421da177e4SLinus Torvalds  * Warning: If you make a record smaller without having copied all the data you
14431da177e4SLinus Torvalds  *	    are interested in the data may be overwritten.
14441da177e4SLinus Torvalds  */
ntfs_attr_record_resize(MFT_RECORD * m,ATTR_RECORD * a,u32 new_size)14451da177e4SLinus Torvalds int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
14461da177e4SLinus Torvalds {
14471da177e4SLinus Torvalds 	ntfs_debug("Entering for new_size %u.", new_size);
14481da177e4SLinus Torvalds 	/* Align to 8 bytes if it is not already done. */
14491da177e4SLinus Torvalds 	if (new_size & 7)
14501da177e4SLinus Torvalds 		new_size = (new_size + 7) & ~7;
14511da177e4SLinus Torvalds 	/* If the actual attribute length has changed, move things around. */
14521da177e4SLinus Torvalds 	if (new_size != le32_to_cpu(a->length)) {
14531da177e4SLinus Torvalds 		u32 new_muse = le32_to_cpu(m->bytes_in_use) -
14541da177e4SLinus Torvalds 				le32_to_cpu(a->length) + new_size;
14551da177e4SLinus Torvalds 		/* Not enough space in this mft record. */
14561da177e4SLinus Torvalds 		if (new_muse > le32_to_cpu(m->bytes_allocated))
14571da177e4SLinus Torvalds 			return -ENOSPC;
14581da177e4SLinus Torvalds 		/* Move attributes following @a to their new location. */
14591da177e4SLinus Torvalds 		memmove((u8*)a + new_size, (u8*)a + le32_to_cpu(a->length),
14601da177e4SLinus Torvalds 				le32_to_cpu(m->bytes_in_use) - ((u8*)a -
14611da177e4SLinus Torvalds 				(u8*)m) - le32_to_cpu(a->length));
14621da177e4SLinus Torvalds 		/* Adjust @m to reflect the change in used space. */
14631da177e4SLinus Torvalds 		m->bytes_in_use = cpu_to_le32(new_muse);
14641da177e4SLinus Torvalds 		/* Adjust @a to reflect the new size. */
14651da177e4SLinus Torvalds 		if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length))
14661da177e4SLinus Torvalds 			a->length = cpu_to_le32(new_size);
14671da177e4SLinus Torvalds 	}
14681da177e4SLinus Torvalds 	return 0;
14691da177e4SLinus Torvalds }
14701da177e4SLinus Torvalds 
14711da177e4SLinus Torvalds /**
14720aacceacSAnton Altaparmakov  * ntfs_resident_attr_value_resize - resize the value of a resident attribute
14730aacceacSAnton Altaparmakov  * @m:		mft record containing attribute record
14740aacceacSAnton Altaparmakov  * @a:		attribute record whose value to resize
14750aacceacSAnton Altaparmakov  * @new_size:	new size in bytes to which to resize the attribute value of @a
14760aacceacSAnton Altaparmakov  *
14770aacceacSAnton Altaparmakov  * Resize the value of the attribute @a in the mft record @m to @new_size bytes.
14780aacceacSAnton Altaparmakov  * If the value is made bigger, the newly allocated space is cleared.
14790aacceacSAnton Altaparmakov  *
14800aacceacSAnton Altaparmakov  * Return 0 on success and -errno on error.  The following error codes are
14810aacceacSAnton Altaparmakov  * defined:
14820aacceacSAnton Altaparmakov  *	-ENOSPC	- Not enough space in the mft record @m to perform the resize.
14830aacceacSAnton Altaparmakov  *
14840aacceacSAnton Altaparmakov  * Note: On error, no modifications have been performed whatsoever.
14850aacceacSAnton Altaparmakov  *
14860aacceacSAnton Altaparmakov  * Warning: If you make a record smaller without having copied all the data you
14870aacceacSAnton Altaparmakov  *	    are interested in the data may be overwritten.
14880aacceacSAnton Altaparmakov  */
ntfs_resident_attr_value_resize(MFT_RECORD * m,ATTR_RECORD * a,const u32 new_size)14890aacceacSAnton Altaparmakov int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
14900aacceacSAnton Altaparmakov 		const u32 new_size)
14910aacceacSAnton Altaparmakov {
14920aacceacSAnton Altaparmakov 	u32 old_size;
14930aacceacSAnton Altaparmakov 
14940aacceacSAnton Altaparmakov 	/* Resize the resident part of the attribute record. */
14950aacceacSAnton Altaparmakov 	if (ntfs_attr_record_resize(m, a,
14960aacceacSAnton Altaparmakov 			le16_to_cpu(a->data.resident.value_offset) + new_size))
14970aacceacSAnton Altaparmakov 		return -ENOSPC;
14980aacceacSAnton Altaparmakov 	/*
14990aacceacSAnton Altaparmakov 	 * The resize succeeded!  If we made the attribute value bigger, clear
15000aacceacSAnton Altaparmakov 	 * the area between the old size and @new_size.
15010aacceacSAnton Altaparmakov 	 */
15020aacceacSAnton Altaparmakov 	old_size = le32_to_cpu(a->data.resident.value_length);
15030aacceacSAnton Altaparmakov 	if (new_size > old_size)
15040aacceacSAnton Altaparmakov 		memset((u8*)a + le16_to_cpu(a->data.resident.value_offset) +
15050aacceacSAnton Altaparmakov 				old_size, 0, new_size - old_size);
15060aacceacSAnton Altaparmakov 	/* Finally update the length of the attribute value. */
15070aacceacSAnton Altaparmakov 	a->data.resident.value_length = cpu_to_le32(new_size);
15080aacceacSAnton Altaparmakov 	return 0;
15090aacceacSAnton Altaparmakov }
15100aacceacSAnton Altaparmakov 
15110aacceacSAnton Altaparmakov /**
15122bfb4fffSAnton Altaparmakov  * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute
15132bfb4fffSAnton Altaparmakov  * @ni:		ntfs inode describing the attribute to convert
15148925d4f0SAnton Altaparmakov  * @data_size:	size of the resident data to copy to the non-resident attribute
15152bfb4fffSAnton Altaparmakov  *
15162bfb4fffSAnton Altaparmakov  * Convert the resident ntfs attribute described by the ntfs inode @ni to a
15172bfb4fffSAnton Altaparmakov  * non-resident one.
15182bfb4fffSAnton Altaparmakov  *
15198925d4f0SAnton Altaparmakov  * @data_size must be equal to the attribute value size.  This is needed since
15208925d4f0SAnton Altaparmakov  * we need to know the size before we can map the mft record and our callers
15218925d4f0SAnton Altaparmakov  * always know it.  The reason we cannot simply read the size from the vfs
15228925d4f0SAnton Altaparmakov  * inode i_size is that this is not necessarily uptodate.  This happens when
15238925d4f0SAnton Altaparmakov  * ntfs_attr_make_non_resident() is called in the ->truncate call path(s).
15248925d4f0SAnton Altaparmakov  *
15252bfb4fffSAnton Altaparmakov  * Return 0 on success and -errno on error.  The following error return codes
15262bfb4fffSAnton Altaparmakov  * are defined:
15272bfb4fffSAnton Altaparmakov  *	-EPERM	- The attribute is not allowed to be non-resident.
15282bfb4fffSAnton Altaparmakov  *	-ENOMEM	- Not enough memory.
15292bfb4fffSAnton Altaparmakov  *	-ENOSPC	- Not enough disk space.
15302bfb4fffSAnton Altaparmakov  *	-EINVAL	- Attribute not defined on the volume.
15312bfb4fffSAnton Altaparmakov  *	-EIO	- I/o error or other error.
153253d59aadSAnton Altaparmakov  * Note that -ENOSPC is also returned in the case that there is not enough
153353d59aadSAnton Altaparmakov  * space in the mft record to do the conversion.  This can happen when the mft
153453d59aadSAnton Altaparmakov  * record is already very full.  The caller is responsible for trying to make
153553d59aadSAnton Altaparmakov  * space in the mft record and trying again.  FIXME: Do we need a separate
153653d59aadSAnton Altaparmakov  * error return code for this kind of -ENOSPC or is it always worth trying
153753d59aadSAnton Altaparmakov  * again in case the attribute may then fit in a resident state so no need to
153853d59aadSAnton Altaparmakov  * make it non-resident at all?  Ho-hum...  (AIA)
15392bfb4fffSAnton Altaparmakov  *
15402bfb4fffSAnton Altaparmakov  * NOTE to self: No changes in the attribute list are required to move from
15412bfb4fffSAnton Altaparmakov  *		 a resident to a non-resident attribute.
15422bfb4fffSAnton Altaparmakov  *
15431b1dcc1bSJes Sorensen  * Locking: - The caller must hold i_mutex on the inode.
15442bfb4fffSAnton Altaparmakov  */
ntfs_attr_make_non_resident(ntfs_inode * ni,const u32 data_size)15458925d4f0SAnton Altaparmakov int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
15462bfb4fffSAnton Altaparmakov {
15472bfb4fffSAnton Altaparmakov 	s64 new_size;
15482bfb4fffSAnton Altaparmakov 	struct inode *vi = VFS_I(ni);
15492bfb4fffSAnton Altaparmakov 	ntfs_volume *vol = ni->vol;
15502bfb4fffSAnton Altaparmakov 	ntfs_inode *base_ni;
15512bfb4fffSAnton Altaparmakov 	MFT_RECORD *m;
15522bfb4fffSAnton Altaparmakov 	ATTR_RECORD *a;
15532bfb4fffSAnton Altaparmakov 	ntfs_attr_search_ctx *ctx;
15542bfb4fffSAnton Altaparmakov 	struct page *page;
15552bfb4fffSAnton Altaparmakov 	runlist_element *rl;
15562bfb4fffSAnton Altaparmakov 	u8 *kaddr;
15572bfb4fffSAnton Altaparmakov 	unsigned long flags;
15582bfb4fffSAnton Altaparmakov 	int mp_size, mp_ofs, name_ofs, arec_size, err, err2;
15592bfb4fffSAnton Altaparmakov 	u32 attr_size;
15602bfb4fffSAnton Altaparmakov 	u8 old_res_attr_flags;
15612bfb4fffSAnton Altaparmakov 
15622bfb4fffSAnton Altaparmakov 	/* Check that the attribute is allowed to be non-resident. */
15632bfb4fffSAnton Altaparmakov 	err = ntfs_attr_can_be_non_resident(vol, ni->type);
15642bfb4fffSAnton Altaparmakov 	if (unlikely(err)) {
15652bfb4fffSAnton Altaparmakov 		if (err == -EPERM)
15662bfb4fffSAnton Altaparmakov 			ntfs_debug("Attribute is not allowed to be "
15672bfb4fffSAnton Altaparmakov 					"non-resident.");
15682bfb4fffSAnton Altaparmakov 		else
15692bfb4fffSAnton Altaparmakov 			ntfs_debug("Attribute not defined on the NTFS "
15702bfb4fffSAnton Altaparmakov 					"volume!");
15712bfb4fffSAnton Altaparmakov 		return err;
15722bfb4fffSAnton Altaparmakov 	}
15732bfb4fffSAnton Altaparmakov 	/*
1574807c453dSAnton Altaparmakov 	 * FIXME: Compressed and encrypted attributes are not supported when
1575807c453dSAnton Altaparmakov 	 * writing and we should never have gotten here for them.
1576807c453dSAnton Altaparmakov 	 */
1577807c453dSAnton Altaparmakov 	BUG_ON(NInoCompressed(ni));
1578807c453dSAnton Altaparmakov 	BUG_ON(NInoEncrypted(ni));
1579807c453dSAnton Altaparmakov 	/*
15802bfb4fffSAnton Altaparmakov 	 * The size needs to be aligned to a cluster boundary for allocation
15812bfb4fffSAnton Altaparmakov 	 * purposes.
15822bfb4fffSAnton Altaparmakov 	 */
15838925d4f0SAnton Altaparmakov 	new_size = (data_size + vol->cluster_size - 1) &
15842bfb4fffSAnton Altaparmakov 			~(vol->cluster_size - 1);
15852bfb4fffSAnton Altaparmakov 	if (new_size > 0) {
15862bfb4fffSAnton Altaparmakov 		/*
15872bfb4fffSAnton Altaparmakov 		 * Will need the page later and since the page lock nests
15882bfb4fffSAnton Altaparmakov 		 * outside all ntfs locks, we need to get the page now.
15892bfb4fffSAnton Altaparmakov 		 */
15902bfb4fffSAnton Altaparmakov 		page = find_or_create_page(vi->i_mapping, 0,
15912bfb4fffSAnton Altaparmakov 				mapping_gfp_mask(vi->i_mapping));
15922bfb4fffSAnton Altaparmakov 		if (unlikely(!page))
15932bfb4fffSAnton Altaparmakov 			return -ENOMEM;
15942bfb4fffSAnton Altaparmakov 		/* Start by allocating clusters to hold the attribute value. */
15952bfb4fffSAnton Altaparmakov 		rl = ntfs_cluster_alloc(vol, 0, new_size >>
1596c49c3111SRichard Knutsson 				vol->cluster_size_bits, -1, DATA_ZONE, true);
15972bfb4fffSAnton Altaparmakov 		if (IS_ERR(rl)) {
15982bfb4fffSAnton Altaparmakov 			err = PTR_ERR(rl);
15992bfb4fffSAnton Altaparmakov 			ntfs_debug("Failed to allocate cluster%s, error code "
1600af859a42SAnton Altaparmakov 					"%i.", (new_size >>
16012bfb4fffSAnton Altaparmakov 					vol->cluster_size_bits) > 1 ? "s" : "",
16022bfb4fffSAnton Altaparmakov 					err);
16032bfb4fffSAnton Altaparmakov 			goto page_err_out;
16042bfb4fffSAnton Altaparmakov 		}
16052bfb4fffSAnton Altaparmakov 	} else {
16062bfb4fffSAnton Altaparmakov 		rl = NULL;
16072bfb4fffSAnton Altaparmakov 		page = NULL;
16082bfb4fffSAnton Altaparmakov 	}
16092bfb4fffSAnton Altaparmakov 	/* Determine the size of the mapping pairs array. */
1610fa3be923SAnton Altaparmakov 	mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, -1);
16112bfb4fffSAnton Altaparmakov 	if (unlikely(mp_size < 0)) {
16122bfb4fffSAnton Altaparmakov 		err = mp_size;
16132bfb4fffSAnton Altaparmakov 		ntfs_debug("Failed to get size for mapping pairs array, error "
16142bfb4fffSAnton Altaparmakov 				"code %i.", err);
16152bfb4fffSAnton Altaparmakov 		goto rl_err_out;
16162bfb4fffSAnton Altaparmakov 	}
16172bfb4fffSAnton Altaparmakov 	down_write(&ni->runlist.lock);
16182bfb4fffSAnton Altaparmakov 	if (!NInoAttr(ni))
16192bfb4fffSAnton Altaparmakov 		base_ni = ni;
16202bfb4fffSAnton Altaparmakov 	else
16212bfb4fffSAnton Altaparmakov 		base_ni = ni->ext.base_ntfs_ino;
16222bfb4fffSAnton Altaparmakov 	m = map_mft_record(base_ni);
16232bfb4fffSAnton Altaparmakov 	if (IS_ERR(m)) {
16242bfb4fffSAnton Altaparmakov 		err = PTR_ERR(m);
16252bfb4fffSAnton Altaparmakov 		m = NULL;
16262bfb4fffSAnton Altaparmakov 		ctx = NULL;
16272bfb4fffSAnton Altaparmakov 		goto err_out;
16282bfb4fffSAnton Altaparmakov 	}
16292bfb4fffSAnton Altaparmakov 	ctx = ntfs_attr_get_search_ctx(base_ni, m);
16302bfb4fffSAnton Altaparmakov 	if (unlikely(!ctx)) {
16312bfb4fffSAnton Altaparmakov 		err = -ENOMEM;
16322bfb4fffSAnton Altaparmakov 		goto err_out;
16332bfb4fffSAnton Altaparmakov 	}
16342bfb4fffSAnton Altaparmakov 	err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
16352bfb4fffSAnton Altaparmakov 			CASE_SENSITIVE, 0, NULL, 0, ctx);
16362bfb4fffSAnton Altaparmakov 	if (unlikely(err)) {
16372bfb4fffSAnton Altaparmakov 		if (err == -ENOENT)
16382bfb4fffSAnton Altaparmakov 			err = -EIO;
16392bfb4fffSAnton Altaparmakov 		goto err_out;
16402bfb4fffSAnton Altaparmakov 	}
16412bfb4fffSAnton Altaparmakov 	m = ctx->mrec;
16422bfb4fffSAnton Altaparmakov 	a = ctx->attr;
16432bfb4fffSAnton Altaparmakov 	BUG_ON(NInoNonResident(ni));
16442bfb4fffSAnton Altaparmakov 	BUG_ON(a->non_resident);
16452bfb4fffSAnton Altaparmakov 	/*
16462bfb4fffSAnton Altaparmakov 	 * Calculate new offsets for the name and the mapping pairs array.
16472bfb4fffSAnton Altaparmakov 	 */
1648807c453dSAnton Altaparmakov 	if (NInoSparse(ni) || NInoCompressed(ni))
1649807c453dSAnton Altaparmakov 		name_ofs = (offsetof(ATTR_REC,
1650807c453dSAnton Altaparmakov 				data.non_resident.compressed_size) +
1651807c453dSAnton Altaparmakov 				sizeof(a->data.non_resident.compressed_size) +
1652807c453dSAnton Altaparmakov 				7) & ~7;
1653807c453dSAnton Altaparmakov 	else
16542bfb4fffSAnton Altaparmakov 		name_ofs = (offsetof(ATTR_REC,
16552bfb4fffSAnton Altaparmakov 				data.non_resident.compressed_size) + 7) & ~7;
16562bfb4fffSAnton Altaparmakov 	mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
16572bfb4fffSAnton Altaparmakov 	/*
16582bfb4fffSAnton Altaparmakov 	 * Determine the size of the resident part of the now non-resident
16592bfb4fffSAnton Altaparmakov 	 * attribute record.
16602bfb4fffSAnton Altaparmakov 	 */
16612bfb4fffSAnton Altaparmakov 	arec_size = (mp_ofs + mp_size + 7) & ~7;
16622bfb4fffSAnton Altaparmakov 	/*
16632bfb4fffSAnton Altaparmakov 	 * If the page is not uptodate bring it uptodate by copying from the
16642bfb4fffSAnton Altaparmakov 	 * attribute value.
16652bfb4fffSAnton Altaparmakov 	 */
16662bfb4fffSAnton Altaparmakov 	attr_size = le32_to_cpu(a->data.resident.value_length);
16678925d4f0SAnton Altaparmakov 	BUG_ON(attr_size != data_size);
16682bfb4fffSAnton Altaparmakov 	if (page && !PageUptodate(page)) {
1669a3ac1414SCong Wang 		kaddr = kmap_atomic(page);
16702bfb4fffSAnton Altaparmakov 		memcpy(kaddr, (u8*)a +
16712bfb4fffSAnton Altaparmakov 				le16_to_cpu(a->data.resident.value_offset),
16722bfb4fffSAnton Altaparmakov 				attr_size);
167309cbfeafSKirill A. Shutemov 		memset(kaddr + attr_size, 0, PAGE_SIZE - attr_size);
1674a3ac1414SCong Wang 		kunmap_atomic(kaddr);
16752bfb4fffSAnton Altaparmakov 		flush_dcache_page(page);
16762bfb4fffSAnton Altaparmakov 		SetPageUptodate(page);
16772bfb4fffSAnton Altaparmakov 	}
16782bfb4fffSAnton Altaparmakov 	/* Backup the attribute flag. */
16792bfb4fffSAnton Altaparmakov 	old_res_attr_flags = a->data.resident.flags;
16802bfb4fffSAnton Altaparmakov 	/* Resize the resident part of the attribute record. */
16812bfb4fffSAnton Altaparmakov 	err = ntfs_attr_record_resize(m, a, arec_size);
16822bfb4fffSAnton Altaparmakov 	if (unlikely(err))
16832bfb4fffSAnton Altaparmakov 		goto err_out;
16842bfb4fffSAnton Altaparmakov 	/*
16852bfb4fffSAnton Altaparmakov 	 * Convert the resident part of the attribute record to describe a
16862bfb4fffSAnton Altaparmakov 	 * non-resident attribute.
16872bfb4fffSAnton Altaparmakov 	 */
16882bfb4fffSAnton Altaparmakov 	a->non_resident = 1;
16892bfb4fffSAnton Altaparmakov 	/* Move the attribute name if it exists and update the offset. */
16902bfb4fffSAnton Altaparmakov 	if (a->name_length)
16912bfb4fffSAnton Altaparmakov 		memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
16922bfb4fffSAnton Altaparmakov 				a->name_length * sizeof(ntfschar));
16932bfb4fffSAnton Altaparmakov 	a->name_offset = cpu_to_le16(name_ofs);
16942bfb4fffSAnton Altaparmakov 	/* Setup the fields specific to non-resident attributes. */
16952bfb4fffSAnton Altaparmakov 	a->data.non_resident.lowest_vcn = 0;
16962bfb4fffSAnton Altaparmakov 	a->data.non_resident.highest_vcn = cpu_to_sle64((new_size - 1) >>
16972bfb4fffSAnton Altaparmakov 			vol->cluster_size_bits);
16982bfb4fffSAnton Altaparmakov 	a->data.non_resident.mapping_pairs_offset = cpu_to_le16(mp_ofs);
16992bfb4fffSAnton Altaparmakov 	memset(&a->data.non_resident.reserved, 0,
17002bfb4fffSAnton Altaparmakov 			sizeof(a->data.non_resident.reserved));
17012bfb4fffSAnton Altaparmakov 	a->data.non_resident.allocated_size = cpu_to_sle64(new_size);
17022bfb4fffSAnton Altaparmakov 	a->data.non_resident.data_size =
17032bfb4fffSAnton Altaparmakov 			a->data.non_resident.initialized_size =
17042bfb4fffSAnton Altaparmakov 			cpu_to_sle64(attr_size);
1705807c453dSAnton Altaparmakov 	if (NInoSparse(ni) || NInoCompressed(ni)) {
1706a0646a1fSAnton Altaparmakov 		a->data.non_resident.compression_unit = 0;
1707a0646a1fSAnton Altaparmakov 		if (NInoCompressed(ni) || vol->major_ver < 3)
1708807c453dSAnton Altaparmakov 			a->data.non_resident.compression_unit = 4;
1709807c453dSAnton Altaparmakov 		a->data.non_resident.compressed_size =
1710807c453dSAnton Altaparmakov 				a->data.non_resident.allocated_size;
1711807c453dSAnton Altaparmakov 	} else
1712807c453dSAnton Altaparmakov 		a->data.non_resident.compression_unit = 0;
17132bfb4fffSAnton Altaparmakov 	/* Generate the mapping pairs array into the attribute record. */
17142bfb4fffSAnton Altaparmakov 	err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs,
1715fa3be923SAnton Altaparmakov 			arec_size - mp_ofs, rl, 0, -1, NULL);
17162bfb4fffSAnton Altaparmakov 	if (unlikely(err)) {
17172bfb4fffSAnton Altaparmakov 		ntfs_debug("Failed to build mapping pairs, error code %i.",
17182bfb4fffSAnton Altaparmakov 				err);
17192bfb4fffSAnton Altaparmakov 		goto undo_err_out;
17202bfb4fffSAnton Altaparmakov 	}
1721905685f6SAnton Altaparmakov 	/* Setup the in-memory attribute structure to be non-resident. */
1722905685f6SAnton Altaparmakov 	ni->runlist.rl = rl;
1723905685f6SAnton Altaparmakov 	write_lock_irqsave(&ni->size_lock, flags);
1724905685f6SAnton Altaparmakov 	ni->allocated_size = new_size;
1725807c453dSAnton Altaparmakov 	if (NInoSparse(ni) || NInoCompressed(ni)) {
1726807c453dSAnton Altaparmakov 		ni->itype.compressed.size = ni->allocated_size;
1727a0646a1fSAnton Altaparmakov 		if (a->data.non_resident.compression_unit) {
1728a0646a1fSAnton Altaparmakov 			ni->itype.compressed.block_size = 1U << (a->data.
1729a0646a1fSAnton Altaparmakov 					non_resident.compression_unit +
1730807c453dSAnton Altaparmakov 					vol->cluster_size_bits);
1731807c453dSAnton Altaparmakov 			ni->itype.compressed.block_size_bits =
1732a0646a1fSAnton Altaparmakov 					ffs(ni->itype.compressed.block_size) -
1733a0646a1fSAnton Altaparmakov 					1;
1734807c453dSAnton Altaparmakov 			ni->itype.compressed.block_clusters = 1U <<
1735807c453dSAnton Altaparmakov 					a->data.non_resident.compression_unit;
1736a0646a1fSAnton Altaparmakov 		} else {
1737a0646a1fSAnton Altaparmakov 			ni->itype.compressed.block_size = 0;
1738a0646a1fSAnton Altaparmakov 			ni->itype.compressed.block_size_bits = 0;
1739a0646a1fSAnton Altaparmakov 			ni->itype.compressed.block_clusters = 0;
1740a0646a1fSAnton Altaparmakov 		}
17412a6fc4e1SAnton Altaparmakov 		vi->i_blocks = ni->itype.compressed.size >> 9;
17422a6fc4e1SAnton Altaparmakov 	} else
17432a6fc4e1SAnton Altaparmakov 		vi->i_blocks = ni->allocated_size >> 9;
1744905685f6SAnton Altaparmakov 	write_unlock_irqrestore(&ni->size_lock, flags);
1745905685f6SAnton Altaparmakov 	/*
1746933906f8SMatthew Wilcox (Oracle) 	 * This needs to be last since the address space operations ->read_folio
1747905685f6SAnton Altaparmakov 	 * and ->writepage can run concurrently with us as they are not
17481b1dcc1bSJes Sorensen 	 * serialized on i_mutex.  Note, we are not allowed to fail once we flip
1749905685f6SAnton Altaparmakov 	 * this switch, which is another reason to do this last.
1750905685f6SAnton Altaparmakov 	 */
1751905685f6SAnton Altaparmakov 	NInoSetNonResident(ni);
17522bfb4fffSAnton Altaparmakov 	/* Mark the mft record dirty, so it gets written back. */
17532bfb4fffSAnton Altaparmakov 	flush_dcache_mft_record_page(ctx->ntfs_ino);
17542bfb4fffSAnton Altaparmakov 	mark_mft_record_dirty(ctx->ntfs_ino);
17552bfb4fffSAnton Altaparmakov 	ntfs_attr_put_search_ctx(ctx);
17562bfb4fffSAnton Altaparmakov 	unmap_mft_record(base_ni);
17572bfb4fffSAnton Altaparmakov 	up_write(&ni->runlist.lock);
17582bfb4fffSAnton Altaparmakov 	if (page) {
17592bfb4fffSAnton Altaparmakov 		set_page_dirty(page);
17602bfb4fffSAnton Altaparmakov 		unlock_page(page);
176109cbfeafSKirill A. Shutemov 		put_page(page);
17622bfb4fffSAnton Altaparmakov 	}
17632bfb4fffSAnton Altaparmakov 	ntfs_debug("Done.");
17642bfb4fffSAnton Altaparmakov 	return 0;
17652bfb4fffSAnton Altaparmakov undo_err_out:
17662bfb4fffSAnton Altaparmakov 	/* Convert the attribute back into a resident attribute. */
17672bfb4fffSAnton Altaparmakov 	a->non_resident = 0;
17682bfb4fffSAnton Altaparmakov 	/* Move the attribute name if it exists and update the offset. */
17692bfb4fffSAnton Altaparmakov 	name_ofs = (offsetof(ATTR_RECORD, data.resident.reserved) +
17702bfb4fffSAnton Altaparmakov 			sizeof(a->data.resident.reserved) + 7) & ~7;
17712bfb4fffSAnton Altaparmakov 	if (a->name_length)
17722bfb4fffSAnton Altaparmakov 		memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
17732bfb4fffSAnton Altaparmakov 				a->name_length * sizeof(ntfschar));
17742bfb4fffSAnton Altaparmakov 	mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
17752bfb4fffSAnton Altaparmakov 	a->name_offset = cpu_to_le16(name_ofs);
17762bfb4fffSAnton Altaparmakov 	arec_size = (mp_ofs + attr_size + 7) & ~7;
17772bfb4fffSAnton Altaparmakov 	/* Resize the resident part of the attribute record. */
17782bfb4fffSAnton Altaparmakov 	err2 = ntfs_attr_record_resize(m, a, arec_size);
17792bfb4fffSAnton Altaparmakov 	if (unlikely(err2)) {
17802bfb4fffSAnton Altaparmakov 		/*
17812bfb4fffSAnton Altaparmakov 		 * This cannot happen (well if memory corruption is at work it
17822bfb4fffSAnton Altaparmakov 		 * could happen in theory), but deal with it as well as we can.
17832bfb4fffSAnton Altaparmakov 		 * If the old size is too small, truncate the attribute,
17842bfb4fffSAnton Altaparmakov 		 * otherwise simply give it a larger allocated size.
17852bfb4fffSAnton Altaparmakov 		 * FIXME: Should check whether chkdsk complains when the
17862bfb4fffSAnton Altaparmakov 		 * allocated size is much bigger than the resident value size.
17872bfb4fffSAnton Altaparmakov 		 */
17882bfb4fffSAnton Altaparmakov 		arec_size = le32_to_cpu(a->length);
17892bfb4fffSAnton Altaparmakov 		if ((mp_ofs + attr_size) > arec_size) {
17902bfb4fffSAnton Altaparmakov 			err2 = attr_size;
17912bfb4fffSAnton Altaparmakov 			attr_size = arec_size - mp_ofs;
17922bfb4fffSAnton Altaparmakov 			ntfs_error(vol->sb, "Failed to undo partial resident "
17932bfb4fffSAnton Altaparmakov 					"to non-resident attribute "
17942bfb4fffSAnton Altaparmakov 					"conversion.  Truncating inode 0x%lx, "
17952bfb4fffSAnton Altaparmakov 					"attribute type 0x%x from %i bytes to "
17962bfb4fffSAnton Altaparmakov 					"%i bytes to maintain metadata "
17972bfb4fffSAnton Altaparmakov 					"consistency.  THIS MEANS YOU ARE "
17982bfb4fffSAnton Altaparmakov 					"LOSING %i BYTES DATA FROM THIS %s.",
17992bfb4fffSAnton Altaparmakov 					vi->i_ino,
18002bfb4fffSAnton Altaparmakov 					(unsigned)le32_to_cpu(ni->type),
18012bfb4fffSAnton Altaparmakov 					err2, attr_size, err2 - attr_size,
18022bfb4fffSAnton Altaparmakov 					((ni->type == AT_DATA) &&
18032bfb4fffSAnton Altaparmakov 					!ni->name_len) ? "FILE": "ATTRIBUTE");
18042bfb4fffSAnton Altaparmakov 			write_lock_irqsave(&ni->size_lock, flags);
18052bfb4fffSAnton Altaparmakov 			ni->initialized_size = attr_size;
18062bfb4fffSAnton Altaparmakov 			i_size_write(vi, attr_size);
18072bfb4fffSAnton Altaparmakov 			write_unlock_irqrestore(&ni->size_lock, flags);
18082bfb4fffSAnton Altaparmakov 		}
18092bfb4fffSAnton Altaparmakov 	}
18102bfb4fffSAnton Altaparmakov 	/* Setup the fields specific to resident attributes. */
18112bfb4fffSAnton Altaparmakov 	a->data.resident.value_length = cpu_to_le32(attr_size);
18122bfb4fffSAnton Altaparmakov 	a->data.resident.value_offset = cpu_to_le16(mp_ofs);
18132bfb4fffSAnton Altaparmakov 	a->data.resident.flags = old_res_attr_flags;
18142bfb4fffSAnton Altaparmakov 	memset(&a->data.resident.reserved, 0,
18152bfb4fffSAnton Altaparmakov 			sizeof(a->data.resident.reserved));
18162bfb4fffSAnton Altaparmakov 	/* Copy the data from the page back to the attribute value. */
18172bfb4fffSAnton Altaparmakov 	if (page) {
1818a3ac1414SCong Wang 		kaddr = kmap_atomic(page);
18192bfb4fffSAnton Altaparmakov 		memcpy((u8*)a + mp_ofs, kaddr, attr_size);
1820a3ac1414SCong Wang 		kunmap_atomic(kaddr);
18212bfb4fffSAnton Altaparmakov 	}
1822905685f6SAnton Altaparmakov 	/* Setup the allocated size in the ntfs inode in case it changed. */
18232bfb4fffSAnton Altaparmakov 	write_lock_irqsave(&ni->size_lock, flags);
18242bfb4fffSAnton Altaparmakov 	ni->allocated_size = arec_size - mp_ofs;
18252bfb4fffSAnton Altaparmakov 	write_unlock_irqrestore(&ni->size_lock, flags);
18262bfb4fffSAnton Altaparmakov 	/* Mark the mft record dirty, so it gets written back. */
18272bfb4fffSAnton Altaparmakov 	flush_dcache_mft_record_page(ctx->ntfs_ino);
18282bfb4fffSAnton Altaparmakov 	mark_mft_record_dirty(ctx->ntfs_ino);
18292bfb4fffSAnton Altaparmakov err_out:
18302bfb4fffSAnton Altaparmakov 	if (ctx)
18312bfb4fffSAnton Altaparmakov 		ntfs_attr_put_search_ctx(ctx);
18322bfb4fffSAnton Altaparmakov 	if (m)
18332bfb4fffSAnton Altaparmakov 		unmap_mft_record(base_ni);
18342bfb4fffSAnton Altaparmakov 	ni->runlist.rl = NULL;
18352bfb4fffSAnton Altaparmakov 	up_write(&ni->runlist.lock);
18362bfb4fffSAnton Altaparmakov rl_err_out:
18372bfb4fffSAnton Altaparmakov 	if (rl) {
18382bfb4fffSAnton Altaparmakov 		if (ntfs_cluster_free_from_rl(vol, rl) < 0) {
18392bfb4fffSAnton Altaparmakov 			ntfs_error(vol->sb, "Failed to release allocated "
18402bfb4fffSAnton Altaparmakov 					"cluster(s) in error code path.  Run "
18412bfb4fffSAnton Altaparmakov 					"chkdsk to recover the lost "
18422bfb4fffSAnton Altaparmakov 					"cluster(s).");
18432bfb4fffSAnton Altaparmakov 			NVolSetErrors(vol);
18442bfb4fffSAnton Altaparmakov 		}
184553d59aadSAnton Altaparmakov 		ntfs_free(rl);
18462bfb4fffSAnton Altaparmakov page_err_out:
18472bfb4fffSAnton Altaparmakov 		unlock_page(page);
184809cbfeafSKirill A. Shutemov 		put_page(page);
18492bfb4fffSAnton Altaparmakov 	}
18502bfb4fffSAnton Altaparmakov 	if (err == -EINVAL)
18512bfb4fffSAnton Altaparmakov 		err = -EIO;
18522bfb4fffSAnton Altaparmakov 	return err;
18532bfb4fffSAnton Altaparmakov }
18542bfb4fffSAnton Altaparmakov 
18552bfb4fffSAnton Altaparmakov /**
18562d86829bSAnton Altaparmakov  * ntfs_attr_extend_allocation - extend the allocated space of an attribute
18572d86829bSAnton Altaparmakov  * @ni:			ntfs inode of the attribute whose allocation to extend
18582d86829bSAnton Altaparmakov  * @new_alloc_size:	new size in bytes to which to extend the allocation to
18592d86829bSAnton Altaparmakov  * @new_data_size:	new size in bytes to which to extend the data to
18602d86829bSAnton Altaparmakov  * @data_start:		beginning of region which is required to be non-sparse
18612d86829bSAnton Altaparmakov  *
18622d86829bSAnton Altaparmakov  * Extend the allocated space of an attribute described by the ntfs inode @ni
18632d86829bSAnton Altaparmakov  * to @new_alloc_size bytes.  If @data_start is -1, the whole extension may be
18642d86829bSAnton Altaparmakov  * implemented as a hole in the file (as long as both the volume and the ntfs
18652d86829bSAnton Altaparmakov  * inode @ni have sparse support enabled).  If @data_start is >= 0, then the
18662d86829bSAnton Altaparmakov  * region between the old allocated size and @data_start - 1 may be made sparse
18672d86829bSAnton Altaparmakov  * but the regions between @data_start and @new_alloc_size must be backed by
18682d86829bSAnton Altaparmakov  * actual clusters.
18692d86829bSAnton Altaparmakov  *
18702d86829bSAnton Altaparmakov  * If @new_data_size is -1, it is ignored.  If it is >= 0, then the data size
18712d86829bSAnton Altaparmakov  * of the attribute is extended to @new_data_size.  Note that the i_size of the
18722d86829bSAnton Altaparmakov  * vfs inode is not updated.  Only the data size in the base attribute record
18732d86829bSAnton Altaparmakov  * is updated.  The caller has to update i_size separately if this is required.
18742d86829bSAnton Altaparmakov  * WARNING: It is a BUG() for @new_data_size to be smaller than the old data
18752d86829bSAnton Altaparmakov  * size as well as for @new_data_size to be greater than @new_alloc_size.
18762d86829bSAnton Altaparmakov  *
18772d86829bSAnton Altaparmakov  * For resident attributes this involves resizing the attribute record and if
18782d86829bSAnton Altaparmakov  * necessary moving it and/or other attributes into extent mft records and/or
18792d86829bSAnton Altaparmakov  * converting the attribute to a non-resident attribute which in turn involves
18802d86829bSAnton Altaparmakov  * extending the allocation of a non-resident attribute as described below.
18812d86829bSAnton Altaparmakov  *
18822d86829bSAnton Altaparmakov  * For non-resident attributes this involves allocating clusters in the data
18832d86829bSAnton Altaparmakov  * zone on the volume (except for regions that are being made sparse) and
18842d86829bSAnton Altaparmakov  * extending the run list to describe the allocated clusters as well as
18852d86829bSAnton Altaparmakov  * updating the mapping pairs array of the attribute.  This in turn involves
18862d86829bSAnton Altaparmakov  * resizing the attribute record and if necessary moving it and/or other
18872d86829bSAnton Altaparmakov  * attributes into extent mft records and/or splitting the attribute record
18882d86829bSAnton Altaparmakov  * into multiple extent attribute records.
18892d86829bSAnton Altaparmakov  *
18902d86829bSAnton Altaparmakov  * Also, the attribute list attribute is updated if present and in some of the
18912d86829bSAnton Altaparmakov  * above cases (the ones where extent mft records/attributes come into play),
18922d86829bSAnton Altaparmakov  * an attribute list attribute is created if not already present.
18932d86829bSAnton Altaparmakov  *
18942d86829bSAnton Altaparmakov  * Return the new allocated size on success and -errno on error.  In the case
18952d86829bSAnton Altaparmakov  * that an error is encountered but a partial extension at least up to
18962d86829bSAnton Altaparmakov  * @data_start (if present) is possible, the allocation is partially extended
18972d86829bSAnton Altaparmakov  * and this is returned.  This means the caller must check the returned size to
18982d86829bSAnton Altaparmakov  * determine if the extension was partial.  If @data_start is -1 then partial
18992d86829bSAnton Altaparmakov  * allocations are not performed.
19002d86829bSAnton Altaparmakov  *
19012d86829bSAnton Altaparmakov  * WARNING: Do not call ntfs_attr_extend_allocation() for $MFT/$DATA.
19022d86829bSAnton Altaparmakov  *
19032d86829bSAnton Altaparmakov  * Locking: This function takes the runlist lock of @ni for writing as well as
19042d86829bSAnton Altaparmakov  * locking the mft record of the base ntfs inode.  These locks are maintained
19052d86829bSAnton Altaparmakov  * throughout execution of the function.  These locks are required so that the
19062d86829bSAnton Altaparmakov  * attribute can be resized safely and so that it can for example be converted
19072d86829bSAnton Altaparmakov  * from resident to non-resident safely.
19082d86829bSAnton Altaparmakov  *
19092d86829bSAnton Altaparmakov  * TODO: At present attribute list attribute handling is not implemented.
19102d86829bSAnton Altaparmakov  *
19112d86829bSAnton Altaparmakov  * TODO: At present it is not safe to call this function for anything other
19122d86829bSAnton Altaparmakov  * than the $DATA attribute(s) of an uncompressed and unencrypted file.
19132d86829bSAnton Altaparmakov  */
ntfs_attr_extend_allocation(ntfs_inode * ni,s64 new_alloc_size,const s64 new_data_size,const s64 data_start)19142d86829bSAnton Altaparmakov s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
19152d86829bSAnton Altaparmakov 		const s64 new_data_size, const s64 data_start)
19162d86829bSAnton Altaparmakov {
19172d86829bSAnton Altaparmakov 	VCN vcn;
19182d86829bSAnton Altaparmakov 	s64 ll, allocated_size, start = data_start;
19192d86829bSAnton Altaparmakov 	struct inode *vi = VFS_I(ni);
19202d86829bSAnton Altaparmakov 	ntfs_volume *vol = ni->vol;
19212d86829bSAnton Altaparmakov 	ntfs_inode *base_ni;
19222d86829bSAnton Altaparmakov 	MFT_RECORD *m;
19232d86829bSAnton Altaparmakov 	ATTR_RECORD *a;
19242d86829bSAnton Altaparmakov 	ntfs_attr_search_ctx *ctx;
19252d86829bSAnton Altaparmakov 	runlist_element *rl, *rl2;
19262d86829bSAnton Altaparmakov 	unsigned long flags;
19272d86829bSAnton Altaparmakov 	int err, mp_size;
19282d86829bSAnton Altaparmakov 	u32 attr_len = 0; /* Silence stupid gcc warning. */
1929c49c3111SRichard Knutsson 	bool mp_rebuilt;
19302d86829bSAnton Altaparmakov 
19315c3bd438SRobert P. J. Day #ifdef DEBUG
19322d86829bSAnton Altaparmakov 	read_lock_irqsave(&ni->size_lock, flags);
19332d86829bSAnton Altaparmakov 	allocated_size = ni->allocated_size;
19342d86829bSAnton Altaparmakov 	read_unlock_irqrestore(&ni->size_lock, flags);
19352d86829bSAnton Altaparmakov 	ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, "
19362d86829bSAnton Altaparmakov 			"old_allocated_size 0x%llx, "
19372d86829bSAnton Altaparmakov 			"new_allocated_size 0x%llx, new_data_size 0x%llx, "
19382d86829bSAnton Altaparmakov 			"data_start 0x%llx.", vi->i_ino,
19392d86829bSAnton Altaparmakov 			(unsigned)le32_to_cpu(ni->type),
19402d86829bSAnton Altaparmakov 			(unsigned long long)allocated_size,
19412d86829bSAnton Altaparmakov 			(unsigned long long)new_alloc_size,
19422d86829bSAnton Altaparmakov 			(unsigned long long)new_data_size,
19432d86829bSAnton Altaparmakov 			(unsigned long long)start);
19442d86829bSAnton Altaparmakov #endif
19452d86829bSAnton Altaparmakov retry_extend:
19462d86829bSAnton Altaparmakov 	/*
19472d86829bSAnton Altaparmakov 	 * For non-resident attributes, @start and @new_size need to be aligned
19482d86829bSAnton Altaparmakov 	 * to cluster boundaries for allocation purposes.
19492d86829bSAnton Altaparmakov 	 */
19502d86829bSAnton Altaparmakov 	if (NInoNonResident(ni)) {
19512d86829bSAnton Altaparmakov 		if (start > 0)
19522d86829bSAnton Altaparmakov 			start &= ~(s64)vol->cluster_size_mask;
19532d86829bSAnton Altaparmakov 		new_alloc_size = (new_alloc_size + vol->cluster_size - 1) &
19542d86829bSAnton Altaparmakov 				~(s64)vol->cluster_size_mask;
19552d86829bSAnton Altaparmakov 	}
19562d86829bSAnton Altaparmakov 	BUG_ON(new_data_size >= 0 && new_data_size > new_alloc_size);
19572d86829bSAnton Altaparmakov 	/* Check if new size is allowed in $AttrDef. */
19582d86829bSAnton Altaparmakov 	err = ntfs_attr_size_bounds_check(vol, ni->type, new_alloc_size);
19592d86829bSAnton Altaparmakov 	if (unlikely(err)) {
19602d86829bSAnton Altaparmakov 		/* Only emit errors when the write will fail completely. */
19612d86829bSAnton Altaparmakov 		read_lock_irqsave(&ni->size_lock, flags);
19622d86829bSAnton Altaparmakov 		allocated_size = ni->allocated_size;
19632d86829bSAnton Altaparmakov 		read_unlock_irqrestore(&ni->size_lock, flags);
19642d86829bSAnton Altaparmakov 		if (start < 0 || start >= allocated_size) {
19652d86829bSAnton Altaparmakov 			if (err == -ERANGE) {
19662d86829bSAnton Altaparmakov 				ntfs_error(vol->sb, "Cannot extend allocation "
19672d86829bSAnton Altaparmakov 						"of inode 0x%lx, attribute "
19682d86829bSAnton Altaparmakov 						"type 0x%x, because the new "
19692d86829bSAnton Altaparmakov 						"allocation would exceed the "
19702d86829bSAnton Altaparmakov 						"maximum allowed size for "
19712d86829bSAnton Altaparmakov 						"this attribute type.",
19722d86829bSAnton Altaparmakov 						vi->i_ino, (unsigned)
19732d86829bSAnton Altaparmakov 						le32_to_cpu(ni->type));
19742d86829bSAnton Altaparmakov 			} else {
19752d86829bSAnton Altaparmakov 				ntfs_error(vol->sb, "Cannot extend allocation "
19762d86829bSAnton Altaparmakov 						"of inode 0x%lx, attribute "
19772d86829bSAnton Altaparmakov 						"type 0x%x, because this "
19782d86829bSAnton Altaparmakov 						"attribute type is not "
19792d86829bSAnton Altaparmakov 						"defined on the NTFS volume.  "
19802d86829bSAnton Altaparmakov 						"Possible corruption!  You "
19812d86829bSAnton Altaparmakov 						"should run chkdsk!",
19822d86829bSAnton Altaparmakov 						vi->i_ino, (unsigned)
19832d86829bSAnton Altaparmakov 						le32_to_cpu(ni->type));
19842d86829bSAnton Altaparmakov 			}
19852d86829bSAnton Altaparmakov 		}
19862d86829bSAnton Altaparmakov 		/* Translate error code to be POSIX conformant for write(2). */
19872d86829bSAnton Altaparmakov 		if (err == -ERANGE)
19882d86829bSAnton Altaparmakov 			err = -EFBIG;
19892d86829bSAnton Altaparmakov 		else
19902d86829bSAnton Altaparmakov 			err = -EIO;
19912d86829bSAnton Altaparmakov 		return err;
19922d86829bSAnton Altaparmakov 	}
19932d86829bSAnton Altaparmakov 	if (!NInoAttr(ni))
19942d86829bSAnton Altaparmakov 		base_ni = ni;
19952d86829bSAnton Altaparmakov 	else
19962d86829bSAnton Altaparmakov 		base_ni = ni->ext.base_ntfs_ino;
19972d86829bSAnton Altaparmakov 	/*
19982d86829bSAnton Altaparmakov 	 * We will be modifying both the runlist (if non-resident) and the mft
19992d86829bSAnton Altaparmakov 	 * record so lock them both down.
20002d86829bSAnton Altaparmakov 	 */
20012d86829bSAnton Altaparmakov 	down_write(&ni->runlist.lock);
20022d86829bSAnton Altaparmakov 	m = map_mft_record(base_ni);
20032d86829bSAnton Altaparmakov 	if (IS_ERR(m)) {
20042d86829bSAnton Altaparmakov 		err = PTR_ERR(m);
20052d86829bSAnton Altaparmakov 		m = NULL;
20062d86829bSAnton Altaparmakov 		ctx = NULL;
20072d86829bSAnton Altaparmakov 		goto err_out;
20082d86829bSAnton Altaparmakov 	}
20092d86829bSAnton Altaparmakov 	ctx = ntfs_attr_get_search_ctx(base_ni, m);
20102d86829bSAnton Altaparmakov 	if (unlikely(!ctx)) {
20112d86829bSAnton Altaparmakov 		err = -ENOMEM;
20122d86829bSAnton Altaparmakov 		goto err_out;
20132d86829bSAnton Altaparmakov 	}
20142d86829bSAnton Altaparmakov 	read_lock_irqsave(&ni->size_lock, flags);
20152d86829bSAnton Altaparmakov 	allocated_size = ni->allocated_size;
20162d86829bSAnton Altaparmakov 	read_unlock_irqrestore(&ni->size_lock, flags);
20172d86829bSAnton Altaparmakov 	/*
20182d86829bSAnton Altaparmakov 	 * If non-resident, seek to the last extent.  If resident, there is
20192d86829bSAnton Altaparmakov 	 * only one extent, so seek to that.
20202d86829bSAnton Altaparmakov 	 */
20212d86829bSAnton Altaparmakov 	vcn = NInoNonResident(ni) ? allocated_size >> vol->cluster_size_bits :
20222d86829bSAnton Altaparmakov 			0;
20232d86829bSAnton Altaparmakov 	/*
20242d86829bSAnton Altaparmakov 	 * Abort if someone did the work whilst we waited for the locks.  If we
20252d86829bSAnton Altaparmakov 	 * just converted the attribute from resident to non-resident it is
20262d86829bSAnton Altaparmakov 	 * likely that exactly this has happened already.  We cannot quite
20272d86829bSAnton Altaparmakov 	 * abort if we need to update the data size.
20282d86829bSAnton Altaparmakov 	 */
20292d86829bSAnton Altaparmakov 	if (unlikely(new_alloc_size <= allocated_size)) {
20302d86829bSAnton Altaparmakov 		ntfs_debug("Allocated size already exceeds requested size.");
20312d86829bSAnton Altaparmakov 		new_alloc_size = allocated_size;
20322d86829bSAnton Altaparmakov 		if (new_data_size < 0)
20332d86829bSAnton Altaparmakov 			goto done;
20342d86829bSAnton Altaparmakov 		/*
20352d86829bSAnton Altaparmakov 		 * We want the first attribute extent so that we can update the
20362d86829bSAnton Altaparmakov 		 * data size.
20372d86829bSAnton Altaparmakov 		 */
20382d86829bSAnton Altaparmakov 		vcn = 0;
20392d86829bSAnton Altaparmakov 	}
20402d86829bSAnton Altaparmakov 	err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
20412d86829bSAnton Altaparmakov 			CASE_SENSITIVE, vcn, NULL, 0, ctx);
20422d86829bSAnton Altaparmakov 	if (unlikely(err)) {
20432d86829bSAnton Altaparmakov 		if (err == -ENOENT)
20442d86829bSAnton Altaparmakov 			err = -EIO;
20452d86829bSAnton Altaparmakov 		goto err_out;
20462d86829bSAnton Altaparmakov 	}
20472d86829bSAnton Altaparmakov 	m = ctx->mrec;
20482d86829bSAnton Altaparmakov 	a = ctx->attr;
20492d86829bSAnton Altaparmakov 	/* Use goto to reduce indentation. */
20502d86829bSAnton Altaparmakov 	if (a->non_resident)
20512d86829bSAnton Altaparmakov 		goto do_non_resident_extend;
20522d86829bSAnton Altaparmakov 	BUG_ON(NInoNonResident(ni));
20532d86829bSAnton Altaparmakov 	/* The total length of the attribute value. */
20542d86829bSAnton Altaparmakov 	attr_len = le32_to_cpu(a->data.resident.value_length);
20552d86829bSAnton Altaparmakov 	/*
20562d86829bSAnton Altaparmakov 	 * Extend the attribute record to be able to store the new attribute
20572d86829bSAnton Altaparmakov 	 * size.  ntfs_attr_record_resize() will not do anything if the size is
20582d86829bSAnton Altaparmakov 	 * not changing.
20592d86829bSAnton Altaparmakov 	 */
20602d86829bSAnton Altaparmakov 	if (new_alloc_size < vol->mft_record_size &&
20612d86829bSAnton Altaparmakov 			!ntfs_attr_record_resize(m, a,
20622d86829bSAnton Altaparmakov 			le16_to_cpu(a->data.resident.value_offset) +
20632d86829bSAnton Altaparmakov 			new_alloc_size)) {
20642d86829bSAnton Altaparmakov 		/* The resize succeeded! */
20652d86829bSAnton Altaparmakov 		write_lock_irqsave(&ni->size_lock, flags);
20662d86829bSAnton Altaparmakov 		ni->allocated_size = le32_to_cpu(a->length) -
20672d86829bSAnton Altaparmakov 				le16_to_cpu(a->data.resident.value_offset);
20682d86829bSAnton Altaparmakov 		write_unlock_irqrestore(&ni->size_lock, flags);
20692d86829bSAnton Altaparmakov 		if (new_data_size >= 0) {
20702d86829bSAnton Altaparmakov 			BUG_ON(new_data_size < attr_len);
20712d86829bSAnton Altaparmakov 			a->data.resident.value_length =
20722d86829bSAnton Altaparmakov 					cpu_to_le32((u32)new_data_size);
20732d86829bSAnton Altaparmakov 		}
20742d86829bSAnton Altaparmakov 		goto flush_done;
20752d86829bSAnton Altaparmakov 	}
20762d86829bSAnton Altaparmakov 	/*
20772d86829bSAnton Altaparmakov 	 * We have to drop all the locks so we can call
20782d86829bSAnton Altaparmakov 	 * ntfs_attr_make_non_resident().  This could be optimised by try-
20792d86829bSAnton Altaparmakov 	 * locking the first page cache page and only if that fails dropping
20802d86829bSAnton Altaparmakov 	 * the locks, locking the page, and redoing all the locking and
20812d86829bSAnton Altaparmakov 	 * lookups.  While this would be a huge optimisation, it is not worth
20822d86829bSAnton Altaparmakov 	 * it as this is definitely a slow code path.
20832d86829bSAnton Altaparmakov 	 */
20842d86829bSAnton Altaparmakov 	ntfs_attr_put_search_ctx(ctx);
20852d86829bSAnton Altaparmakov 	unmap_mft_record(base_ni);
20862d86829bSAnton Altaparmakov 	up_write(&ni->runlist.lock);
20872d86829bSAnton Altaparmakov 	/*
20882d86829bSAnton Altaparmakov 	 * Not enough space in the mft record, try to make the attribute
20892d86829bSAnton Altaparmakov 	 * non-resident and if successful restart the extension process.
20902d86829bSAnton Altaparmakov 	 */
20912d86829bSAnton Altaparmakov 	err = ntfs_attr_make_non_resident(ni, attr_len);
20922d86829bSAnton Altaparmakov 	if (likely(!err))
20932d86829bSAnton Altaparmakov 		goto retry_extend;
20942d86829bSAnton Altaparmakov 	/*
20952d86829bSAnton Altaparmakov 	 * Could not make non-resident.  If this is due to this not being
20962d86829bSAnton Altaparmakov 	 * permitted for this attribute type or there not being enough space,
20972d86829bSAnton Altaparmakov 	 * try to make other attributes non-resident.  Otherwise fail.
20982d86829bSAnton Altaparmakov 	 */
20992d86829bSAnton Altaparmakov 	if (unlikely(err != -EPERM && err != -ENOSPC)) {
21002d86829bSAnton Altaparmakov 		/* Only emit errors when the write will fail completely. */
21012d86829bSAnton Altaparmakov 		read_lock_irqsave(&ni->size_lock, flags);
21022d86829bSAnton Altaparmakov 		allocated_size = ni->allocated_size;
21032d86829bSAnton Altaparmakov 		read_unlock_irqrestore(&ni->size_lock, flags);
21042d86829bSAnton Altaparmakov 		if (start < 0 || start >= allocated_size)
21052d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "Cannot extend allocation of "
21062d86829bSAnton Altaparmakov 					"inode 0x%lx, attribute type 0x%x, "
21072d86829bSAnton Altaparmakov 					"because the conversion from resident "
21082d86829bSAnton Altaparmakov 					"to non-resident attribute failed "
21092d86829bSAnton Altaparmakov 					"with error code %i.", vi->i_ino,
21102d86829bSAnton Altaparmakov 					(unsigned)le32_to_cpu(ni->type), err);
21112d86829bSAnton Altaparmakov 		if (err != -ENOMEM)
21122d86829bSAnton Altaparmakov 			err = -EIO;
21132d86829bSAnton Altaparmakov 		goto conv_err_out;
21142d86829bSAnton Altaparmakov 	}
21152d86829bSAnton Altaparmakov 	/* TODO: Not implemented from here, abort. */
21162d86829bSAnton Altaparmakov 	read_lock_irqsave(&ni->size_lock, flags);
21172d86829bSAnton Altaparmakov 	allocated_size = ni->allocated_size;
21182d86829bSAnton Altaparmakov 	read_unlock_irqrestore(&ni->size_lock, flags);
21192d86829bSAnton Altaparmakov 	if (start < 0 || start >= allocated_size) {
21202d86829bSAnton Altaparmakov 		if (err == -ENOSPC)
21212d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "Not enough space in the mft "
21222d86829bSAnton Altaparmakov 					"record/on disk for the non-resident "
21232d86829bSAnton Altaparmakov 					"attribute value.  This case is not "
21242d86829bSAnton Altaparmakov 					"implemented yet.");
21252d86829bSAnton Altaparmakov 		else /* if (err == -EPERM) */
21262d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "This attribute type may not be "
21272d86829bSAnton Altaparmakov 					"non-resident.  This case is not "
21282d86829bSAnton Altaparmakov 					"implemented yet.");
21292d86829bSAnton Altaparmakov 	}
21302d86829bSAnton Altaparmakov 	err = -EOPNOTSUPP;
21312d86829bSAnton Altaparmakov 	goto conv_err_out;
21322d86829bSAnton Altaparmakov #if 0
21332d86829bSAnton Altaparmakov 	// TODO: Attempt to make other attributes non-resident.
21342d86829bSAnton Altaparmakov 	if (!err)
21352d86829bSAnton Altaparmakov 		goto do_resident_extend;
21362d86829bSAnton Altaparmakov 	/*
21372d86829bSAnton Altaparmakov 	 * Both the attribute list attribute and the standard information
21382d86829bSAnton Altaparmakov 	 * attribute must remain in the base inode.  Thus, if this is one of
21392d86829bSAnton Altaparmakov 	 * these attributes, we have to try to move other attributes out into
21402d86829bSAnton Altaparmakov 	 * extent mft records instead.
21412d86829bSAnton Altaparmakov 	 */
21422d86829bSAnton Altaparmakov 	if (ni->type == AT_ATTRIBUTE_LIST ||
21432d86829bSAnton Altaparmakov 			ni->type == AT_STANDARD_INFORMATION) {
21442d86829bSAnton Altaparmakov 		// TODO: Attempt to move other attributes into extent mft
21452d86829bSAnton Altaparmakov 		// records.
21462d86829bSAnton Altaparmakov 		err = -EOPNOTSUPP;
21472d86829bSAnton Altaparmakov 		if (!err)
21482d86829bSAnton Altaparmakov 			goto do_resident_extend;
21492d86829bSAnton Altaparmakov 		goto err_out;
21502d86829bSAnton Altaparmakov 	}
21512d86829bSAnton Altaparmakov 	// TODO: Attempt to move this attribute to an extent mft record, but
21522d86829bSAnton Altaparmakov 	// only if it is not already the only attribute in an mft record in
21532d86829bSAnton Altaparmakov 	// which case there would be nothing to gain.
21542d86829bSAnton Altaparmakov 	err = -EOPNOTSUPP;
21552d86829bSAnton Altaparmakov 	if (!err)
21562d86829bSAnton Altaparmakov 		goto do_resident_extend;
21572d86829bSAnton Altaparmakov 	/* There is nothing we can do to make enough space. )-: */
21582d86829bSAnton Altaparmakov 	goto err_out;
21592d86829bSAnton Altaparmakov #endif
21602d86829bSAnton Altaparmakov do_non_resident_extend:
21612d86829bSAnton Altaparmakov 	BUG_ON(!NInoNonResident(ni));
21622d86829bSAnton Altaparmakov 	if (new_alloc_size == allocated_size) {
21632d86829bSAnton Altaparmakov 		BUG_ON(vcn);
21642d86829bSAnton Altaparmakov 		goto alloc_done;
21652d86829bSAnton Altaparmakov 	}
21662d86829bSAnton Altaparmakov 	/*
21672d86829bSAnton Altaparmakov 	 * If the data starts after the end of the old allocation, this is a
21682d86829bSAnton Altaparmakov 	 * $DATA attribute and sparse attributes are enabled on the volume and
21692d86829bSAnton Altaparmakov 	 * for this inode, then create a sparse region between the old
21702d86829bSAnton Altaparmakov 	 * allocated size and the start of the data.  Otherwise simply proceed
21712d86829bSAnton Altaparmakov 	 * with filling the whole space between the old allocated size and the
21722d86829bSAnton Altaparmakov 	 * new allocated size with clusters.
21732d86829bSAnton Altaparmakov 	 */
21742d86829bSAnton Altaparmakov 	if ((start >= 0 && start <= allocated_size) || ni->type != AT_DATA ||
21752d86829bSAnton Altaparmakov 			!NVolSparseEnabled(vol) || NInoSparseDisabled(ni))
21762d86829bSAnton Altaparmakov 		goto skip_sparse;
21772d86829bSAnton Altaparmakov 	// TODO: This is not implemented yet.  We just fill in with real
21782d86829bSAnton Altaparmakov 	// clusters for now...
21792d86829bSAnton Altaparmakov 	ntfs_debug("Inserting holes is not-implemented yet.  Falling back to "
21802d86829bSAnton Altaparmakov 			"allocating real clusters instead.");
21812d86829bSAnton Altaparmakov skip_sparse:
21822d86829bSAnton Altaparmakov 	rl = ni->runlist.rl;
21832d86829bSAnton Altaparmakov 	if (likely(rl)) {
21842d86829bSAnton Altaparmakov 		/* Seek to the end of the runlist. */
21852d86829bSAnton Altaparmakov 		while (rl->length)
21862d86829bSAnton Altaparmakov 			rl++;
21872d86829bSAnton Altaparmakov 	}
21882d86829bSAnton Altaparmakov 	/* If this attribute extent is not mapped, map it now. */
21892d86829bSAnton Altaparmakov 	if (unlikely(!rl || rl->lcn == LCN_RL_NOT_MAPPED ||
21902d86829bSAnton Altaparmakov 			(rl->lcn == LCN_ENOENT && rl > ni->runlist.rl &&
21912d86829bSAnton Altaparmakov 			(rl-1)->lcn == LCN_RL_NOT_MAPPED))) {
21922d86829bSAnton Altaparmakov 		if (!rl && !allocated_size)
21932d86829bSAnton Altaparmakov 			goto first_alloc;
21942d86829bSAnton Altaparmakov 		rl = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl);
21952d86829bSAnton Altaparmakov 		if (IS_ERR(rl)) {
21962d86829bSAnton Altaparmakov 			err = PTR_ERR(rl);
21972d86829bSAnton Altaparmakov 			if (start < 0 || start >= allocated_size)
21982d86829bSAnton Altaparmakov 				ntfs_error(vol->sb, "Cannot extend allocation "
21992d86829bSAnton Altaparmakov 						"of inode 0x%lx, attribute "
22002d86829bSAnton Altaparmakov 						"type 0x%x, because the "
22012d86829bSAnton Altaparmakov 						"mapping of a runlist "
22022d86829bSAnton Altaparmakov 						"fragment failed with error "
22032d86829bSAnton Altaparmakov 						"code %i.", vi->i_ino,
22042d86829bSAnton Altaparmakov 						(unsigned)le32_to_cpu(ni->type),
22052d86829bSAnton Altaparmakov 						err);
22062d86829bSAnton Altaparmakov 			if (err != -ENOMEM)
22072d86829bSAnton Altaparmakov 				err = -EIO;
22082d86829bSAnton Altaparmakov 			goto err_out;
22092d86829bSAnton Altaparmakov 		}
22102d86829bSAnton Altaparmakov 		ni->runlist.rl = rl;
22112d86829bSAnton Altaparmakov 		/* Seek to the end of the runlist. */
22122d86829bSAnton Altaparmakov 		while (rl->length)
22132d86829bSAnton Altaparmakov 			rl++;
22142d86829bSAnton Altaparmakov 	}
22152d86829bSAnton Altaparmakov 	/*
22162d86829bSAnton Altaparmakov 	 * We now know the runlist of the last extent is mapped and @rl is at
22172d86829bSAnton Altaparmakov 	 * the end of the runlist.  We want to begin allocating clusters
22182d86829bSAnton Altaparmakov 	 * starting at the last allocated cluster to reduce fragmentation.  If
22192d86829bSAnton Altaparmakov 	 * there are no valid LCNs in the attribute we let the cluster
22202d86829bSAnton Altaparmakov 	 * allocator choose the starting cluster.
22212d86829bSAnton Altaparmakov 	 */
22222d86829bSAnton Altaparmakov 	/* If the last LCN is a hole or simillar seek back to last real LCN. */
22232d86829bSAnton Altaparmakov 	while (rl->lcn < 0 && rl > ni->runlist.rl)
22242d86829bSAnton Altaparmakov 		rl--;
22252d86829bSAnton Altaparmakov first_alloc:
22262d86829bSAnton Altaparmakov 	// FIXME: Need to implement partial allocations so at least part of the
22272d86829bSAnton Altaparmakov 	// write can be performed when start >= 0.  (Needed for POSIX write(2)
22282d86829bSAnton Altaparmakov 	// conformance.)
22292d86829bSAnton Altaparmakov 	rl2 = ntfs_cluster_alloc(vol, allocated_size >> vol->cluster_size_bits,
22302d86829bSAnton Altaparmakov 			(new_alloc_size - allocated_size) >>
22312d86829bSAnton Altaparmakov 			vol->cluster_size_bits, (rl && (rl->lcn >= 0)) ?
2232c49c3111SRichard Knutsson 			rl->lcn + rl->length : -1, DATA_ZONE, true);
22332d86829bSAnton Altaparmakov 	if (IS_ERR(rl2)) {
22342d86829bSAnton Altaparmakov 		err = PTR_ERR(rl2);
22352d86829bSAnton Altaparmakov 		if (start < 0 || start >= allocated_size)
22362d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "Cannot extend allocation of "
22372d86829bSAnton Altaparmakov 					"inode 0x%lx, attribute type 0x%x, "
22382d86829bSAnton Altaparmakov 					"because the allocation of clusters "
22392d86829bSAnton Altaparmakov 					"failed with error code %i.", vi->i_ino,
22402d86829bSAnton Altaparmakov 					(unsigned)le32_to_cpu(ni->type), err);
22412d86829bSAnton Altaparmakov 		if (err != -ENOMEM && err != -ENOSPC)
22422d86829bSAnton Altaparmakov 			err = -EIO;
22432d86829bSAnton Altaparmakov 		goto err_out;
22442d86829bSAnton Altaparmakov 	}
22452d86829bSAnton Altaparmakov 	rl = ntfs_runlists_merge(ni->runlist.rl, rl2);
22462d86829bSAnton Altaparmakov 	if (IS_ERR(rl)) {
22472d86829bSAnton Altaparmakov 		err = PTR_ERR(rl);
22482d86829bSAnton Altaparmakov 		if (start < 0 || start >= allocated_size)
22492d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "Cannot extend allocation of "
22502d86829bSAnton Altaparmakov 					"inode 0x%lx, attribute type 0x%x, "
22512d86829bSAnton Altaparmakov 					"because the runlist merge failed "
22522d86829bSAnton Altaparmakov 					"with error code %i.", vi->i_ino,
22532d86829bSAnton Altaparmakov 					(unsigned)le32_to_cpu(ni->type), err);
22542d86829bSAnton Altaparmakov 		if (err != -ENOMEM)
22552d86829bSAnton Altaparmakov 			err = -EIO;
22562d86829bSAnton Altaparmakov 		if (ntfs_cluster_free_from_rl(vol, rl2)) {
22572d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "Failed to release allocated "
22582d86829bSAnton Altaparmakov 					"cluster(s) in error code path.  Run "
22592d86829bSAnton Altaparmakov 					"chkdsk to recover the lost "
22602d86829bSAnton Altaparmakov 					"cluster(s).");
22612d86829bSAnton Altaparmakov 			NVolSetErrors(vol);
22622d86829bSAnton Altaparmakov 		}
22632d86829bSAnton Altaparmakov 		ntfs_free(rl2);
22642d86829bSAnton Altaparmakov 		goto err_out;
22652d86829bSAnton Altaparmakov 	}
22662d86829bSAnton Altaparmakov 	ni->runlist.rl = rl;
22672d86829bSAnton Altaparmakov 	ntfs_debug("Allocated 0x%llx clusters.", (long long)(new_alloc_size -
22682d86829bSAnton Altaparmakov 			allocated_size) >> vol->cluster_size_bits);
22692d86829bSAnton Altaparmakov 	/* Find the runlist element with which the attribute extent starts. */
22702d86829bSAnton Altaparmakov 	ll = sle64_to_cpu(a->data.non_resident.lowest_vcn);
22712d86829bSAnton Altaparmakov 	rl2 = ntfs_rl_find_vcn_nolock(rl, ll);
22722d86829bSAnton Altaparmakov 	BUG_ON(!rl2);
22732d86829bSAnton Altaparmakov 	BUG_ON(!rl2->length);
22742d86829bSAnton Altaparmakov 	BUG_ON(rl2->lcn < LCN_HOLE);
2275c49c3111SRichard Knutsson 	mp_rebuilt = false;
22762d86829bSAnton Altaparmakov 	/* Get the size for the new mapping pairs array for this extent. */
22772d86829bSAnton Altaparmakov 	mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1);
22782d86829bSAnton Altaparmakov 	if (unlikely(mp_size <= 0)) {
22792d86829bSAnton Altaparmakov 		err = mp_size;
22802d86829bSAnton Altaparmakov 		if (start < 0 || start >= allocated_size)
22812d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "Cannot extend allocation of "
22822d86829bSAnton Altaparmakov 					"inode 0x%lx, attribute type 0x%x, "
22832d86829bSAnton Altaparmakov 					"because determining the size for the "
22842d86829bSAnton Altaparmakov 					"mapping pairs failed with error code "
22852d86829bSAnton Altaparmakov 					"%i.", vi->i_ino,
22862d86829bSAnton Altaparmakov 					(unsigned)le32_to_cpu(ni->type), err);
22872d86829bSAnton Altaparmakov 		err = -EIO;
22882d86829bSAnton Altaparmakov 		goto undo_alloc;
22892d86829bSAnton Altaparmakov 	}
22902d86829bSAnton Altaparmakov 	/* Extend the attribute record to fit the bigger mapping pairs array. */
22912d86829bSAnton Altaparmakov 	attr_len = le32_to_cpu(a->length);
22922d86829bSAnton Altaparmakov 	err = ntfs_attr_record_resize(m, a, mp_size +
22932d86829bSAnton Altaparmakov 			le16_to_cpu(a->data.non_resident.mapping_pairs_offset));
22942d86829bSAnton Altaparmakov 	if (unlikely(err)) {
22952d86829bSAnton Altaparmakov 		BUG_ON(err != -ENOSPC);
22962d86829bSAnton Altaparmakov 		// TODO: Deal with this by moving this extent to a new mft
22972d86829bSAnton Altaparmakov 		// record or by starting a new extent in a new mft record,
22982d86829bSAnton Altaparmakov 		// possibly by extending this extent partially and filling it
22992d86829bSAnton Altaparmakov 		// and creating a new extent for the remainder, or by making
23002d86829bSAnton Altaparmakov 		// other attributes non-resident and/or by moving other
23012d86829bSAnton Altaparmakov 		// attributes out of this mft record.
23022d86829bSAnton Altaparmakov 		if (start < 0 || start >= allocated_size)
23032d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "Not enough space in the mft "
23042d86829bSAnton Altaparmakov 					"record for the extended attribute "
23052d86829bSAnton Altaparmakov 					"record.  This case is not "
23062d86829bSAnton Altaparmakov 					"implemented yet.");
23072d86829bSAnton Altaparmakov 		err = -EOPNOTSUPP;
23082d86829bSAnton Altaparmakov 		goto undo_alloc;
23092d86829bSAnton Altaparmakov 	}
2310c49c3111SRichard Knutsson 	mp_rebuilt = true;
23112d86829bSAnton Altaparmakov 	/* Generate the mapping pairs array directly into the attr record. */
23122d86829bSAnton Altaparmakov 	err = ntfs_mapping_pairs_build(vol, (u8*)a +
23132d86829bSAnton Altaparmakov 			le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
23142d86829bSAnton Altaparmakov 			mp_size, rl2, ll, -1, NULL);
23152d86829bSAnton Altaparmakov 	if (unlikely(err)) {
23162d86829bSAnton Altaparmakov 		if (start < 0 || start >= allocated_size)
23172d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "Cannot extend allocation of "
23182d86829bSAnton Altaparmakov 					"inode 0x%lx, attribute type 0x%x, "
23192d86829bSAnton Altaparmakov 					"because building the mapping pairs "
23202d86829bSAnton Altaparmakov 					"failed with error code %i.", vi->i_ino,
23212d86829bSAnton Altaparmakov 					(unsigned)le32_to_cpu(ni->type), err);
23222d86829bSAnton Altaparmakov 		err = -EIO;
23232d86829bSAnton Altaparmakov 		goto undo_alloc;
23242d86829bSAnton Altaparmakov 	}
23252d86829bSAnton Altaparmakov 	/* Update the highest_vcn. */
23262d86829bSAnton Altaparmakov 	a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >>
23272d86829bSAnton Altaparmakov 			vol->cluster_size_bits) - 1);
23282d86829bSAnton Altaparmakov 	/*
23292d86829bSAnton Altaparmakov 	 * We now have extended the allocated size of the attribute.  Reflect
23302d86829bSAnton Altaparmakov 	 * this in the ntfs_inode structure and the attribute record.
23312d86829bSAnton Altaparmakov 	 */
23322d86829bSAnton Altaparmakov 	if (a->data.non_resident.lowest_vcn) {
23332d86829bSAnton Altaparmakov 		/*
23342d86829bSAnton Altaparmakov 		 * We are not in the first attribute extent, switch to it, but
23352d86829bSAnton Altaparmakov 		 * first ensure the changes will make it to disk later.
23362d86829bSAnton Altaparmakov 		 */
23372d86829bSAnton Altaparmakov 		flush_dcache_mft_record_page(ctx->ntfs_ino);
23382d86829bSAnton Altaparmakov 		mark_mft_record_dirty(ctx->ntfs_ino);
23392d86829bSAnton Altaparmakov 		ntfs_attr_reinit_search_ctx(ctx);
23402d86829bSAnton Altaparmakov 		err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
23412d86829bSAnton Altaparmakov 				CASE_SENSITIVE, 0, NULL, 0, ctx);
23422d86829bSAnton Altaparmakov 		if (unlikely(err))
23432d86829bSAnton Altaparmakov 			goto restore_undo_alloc;
23442d86829bSAnton Altaparmakov 		/* @m is not used any more so no need to set it. */
23452d86829bSAnton Altaparmakov 		a = ctx->attr;
23462d86829bSAnton Altaparmakov 	}
23472d86829bSAnton Altaparmakov 	write_lock_irqsave(&ni->size_lock, flags);
23482d86829bSAnton Altaparmakov 	ni->allocated_size = new_alloc_size;
23492d86829bSAnton Altaparmakov 	a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size);
23502d86829bSAnton Altaparmakov 	/*
23512d86829bSAnton Altaparmakov 	 * FIXME: This would fail if @ni is a directory, $MFT, or an index,
23522d86829bSAnton Altaparmakov 	 * since those can have sparse/compressed set.  For example can be
23532d86829bSAnton Altaparmakov 	 * set compressed even though it is not compressed itself and in that
23542d86829bSAnton Altaparmakov 	 * case the bit means that files are to be created compressed in the
23552d86829bSAnton Altaparmakov 	 * directory...  At present this is ok as this code is only called for
23562d86829bSAnton Altaparmakov 	 * regular files, and only for their $DATA attribute(s).
23572d86829bSAnton Altaparmakov 	 * FIXME: The calculation is wrong if we created a hole above.  For now
23582d86829bSAnton Altaparmakov 	 * it does not matter as we never create holes.
23592d86829bSAnton Altaparmakov 	 */
23602d86829bSAnton Altaparmakov 	if (NInoSparse(ni) || NInoCompressed(ni)) {
23612d86829bSAnton Altaparmakov 		ni->itype.compressed.size += new_alloc_size - allocated_size;
23622d86829bSAnton Altaparmakov 		a->data.non_resident.compressed_size =
23632d86829bSAnton Altaparmakov 				cpu_to_sle64(ni->itype.compressed.size);
23642d86829bSAnton Altaparmakov 		vi->i_blocks = ni->itype.compressed.size >> 9;
23652d86829bSAnton Altaparmakov 	} else
23662d86829bSAnton Altaparmakov 		vi->i_blocks = new_alloc_size >> 9;
23672d86829bSAnton Altaparmakov 	write_unlock_irqrestore(&ni->size_lock, flags);
23682d86829bSAnton Altaparmakov alloc_done:
23692d86829bSAnton Altaparmakov 	if (new_data_size >= 0) {
23702d86829bSAnton Altaparmakov 		BUG_ON(new_data_size <
23712d86829bSAnton Altaparmakov 				sle64_to_cpu(a->data.non_resident.data_size));
23722d86829bSAnton Altaparmakov 		a->data.non_resident.data_size = cpu_to_sle64(new_data_size);
23732d86829bSAnton Altaparmakov 	}
23742d86829bSAnton Altaparmakov flush_done:
23752d86829bSAnton Altaparmakov 	/* Ensure the changes make it to disk. */
23762d86829bSAnton Altaparmakov 	flush_dcache_mft_record_page(ctx->ntfs_ino);
23772d86829bSAnton Altaparmakov 	mark_mft_record_dirty(ctx->ntfs_ino);
23782d86829bSAnton Altaparmakov done:
23792d86829bSAnton Altaparmakov 	ntfs_attr_put_search_ctx(ctx);
23802d86829bSAnton Altaparmakov 	unmap_mft_record(base_ni);
23812d86829bSAnton Altaparmakov 	up_write(&ni->runlist.lock);
23822d86829bSAnton Altaparmakov 	ntfs_debug("Done, new_allocated_size 0x%llx.",
23832d86829bSAnton Altaparmakov 			(unsigned long long)new_alloc_size);
23842d86829bSAnton Altaparmakov 	return new_alloc_size;
23852d86829bSAnton Altaparmakov restore_undo_alloc:
23862d86829bSAnton Altaparmakov 	if (start < 0 || start >= allocated_size)
23872d86829bSAnton Altaparmakov 		ntfs_error(vol->sb, "Cannot complete extension of allocation "
23882d86829bSAnton Altaparmakov 				"of inode 0x%lx, attribute type 0x%x, because "
23892d86829bSAnton Altaparmakov 				"lookup of first attribute extent failed with "
23902d86829bSAnton Altaparmakov 				"error code %i.", vi->i_ino,
23912d86829bSAnton Altaparmakov 				(unsigned)le32_to_cpu(ni->type), err);
23922d86829bSAnton Altaparmakov 	if (err == -ENOENT)
23932d86829bSAnton Altaparmakov 		err = -EIO;
23942d86829bSAnton Altaparmakov 	ntfs_attr_reinit_search_ctx(ctx);
23952d86829bSAnton Altaparmakov 	if (ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE,
23962d86829bSAnton Altaparmakov 			allocated_size >> vol->cluster_size_bits, NULL, 0,
23972d86829bSAnton Altaparmakov 			ctx)) {
23982d86829bSAnton Altaparmakov 		ntfs_error(vol->sb, "Failed to find last attribute extent of "
23992d86829bSAnton Altaparmakov 				"attribute in error code path.  Run chkdsk to "
24002d86829bSAnton Altaparmakov 				"recover.");
24012d86829bSAnton Altaparmakov 		write_lock_irqsave(&ni->size_lock, flags);
24022d86829bSAnton Altaparmakov 		ni->allocated_size = new_alloc_size;
24032d86829bSAnton Altaparmakov 		/*
24042d86829bSAnton Altaparmakov 		 * FIXME: This would fail if @ni is a directory...  See above.
24052d86829bSAnton Altaparmakov 		 * FIXME: The calculation is wrong if we created a hole above.
24062d86829bSAnton Altaparmakov 		 * For now it does not matter as we never create holes.
24072d86829bSAnton Altaparmakov 		 */
24082d86829bSAnton Altaparmakov 		if (NInoSparse(ni) || NInoCompressed(ni)) {
24092d86829bSAnton Altaparmakov 			ni->itype.compressed.size += new_alloc_size -
24102d86829bSAnton Altaparmakov 					allocated_size;
24112d86829bSAnton Altaparmakov 			vi->i_blocks = ni->itype.compressed.size >> 9;
24122d86829bSAnton Altaparmakov 		} else
24132d86829bSAnton Altaparmakov 			vi->i_blocks = new_alloc_size >> 9;
24142d86829bSAnton Altaparmakov 		write_unlock_irqrestore(&ni->size_lock, flags);
24152d86829bSAnton Altaparmakov 		ntfs_attr_put_search_ctx(ctx);
24162d86829bSAnton Altaparmakov 		unmap_mft_record(base_ni);
24172d86829bSAnton Altaparmakov 		up_write(&ni->runlist.lock);
24182d86829bSAnton Altaparmakov 		/*
24192d86829bSAnton Altaparmakov 		 * The only thing that is now wrong is the allocated size of the
24202d86829bSAnton Altaparmakov 		 * base attribute extent which chkdsk should be able to fix.
24212d86829bSAnton Altaparmakov 		 */
24222d86829bSAnton Altaparmakov 		NVolSetErrors(vol);
24232d86829bSAnton Altaparmakov 		return err;
24242d86829bSAnton Altaparmakov 	}
24252d86829bSAnton Altaparmakov 	ctx->attr->data.non_resident.highest_vcn = cpu_to_sle64(
24262d86829bSAnton Altaparmakov 			(allocated_size >> vol->cluster_size_bits) - 1);
24272d86829bSAnton Altaparmakov undo_alloc:
24282d86829bSAnton Altaparmakov 	ll = allocated_size >> vol->cluster_size_bits;
24292d86829bSAnton Altaparmakov 	if (ntfs_cluster_free(ni, ll, -1, ctx) < 0) {
24302d86829bSAnton Altaparmakov 		ntfs_error(vol->sb, "Failed to release allocated cluster(s) "
24312d86829bSAnton Altaparmakov 				"in error code path.  Run chkdsk to recover "
24322d86829bSAnton Altaparmakov 				"the lost cluster(s).");
24332d86829bSAnton Altaparmakov 		NVolSetErrors(vol);
24342d86829bSAnton Altaparmakov 	}
24352d86829bSAnton Altaparmakov 	m = ctx->mrec;
24362d86829bSAnton Altaparmakov 	a = ctx->attr;
24372d86829bSAnton Altaparmakov 	/*
24382d86829bSAnton Altaparmakov 	 * If the runlist truncation fails and/or the search context is no
24392d86829bSAnton Altaparmakov 	 * longer valid, we cannot resize the attribute record or build the
24402d86829bSAnton Altaparmakov 	 * mapping pairs array thus we mark the inode bad so that no access to
24412d86829bSAnton Altaparmakov 	 * the freed clusters can happen.
24422d86829bSAnton Altaparmakov 	 */
24432d86829bSAnton Altaparmakov 	if (ntfs_rl_truncate_nolock(vol, &ni->runlist, ll) || IS_ERR(m)) {
24442d86829bSAnton Altaparmakov 		ntfs_error(vol->sb, "Failed to %s in error code path.  Run "
24452d86829bSAnton Altaparmakov 				"chkdsk to recover.", IS_ERR(m) ?
24462d86829bSAnton Altaparmakov 				"restore attribute search context" :
24472d86829bSAnton Altaparmakov 				"truncate attribute runlist");
24482d86829bSAnton Altaparmakov 		NVolSetErrors(vol);
24492d86829bSAnton Altaparmakov 	} else if (mp_rebuilt) {
24502d86829bSAnton Altaparmakov 		if (ntfs_attr_record_resize(m, a, attr_len)) {
24512d86829bSAnton Altaparmakov 			ntfs_error(vol->sb, "Failed to restore attribute "
24522d86829bSAnton Altaparmakov 					"record in error code path.  Run "
24532d86829bSAnton Altaparmakov 					"chkdsk to recover.");
24542d86829bSAnton Altaparmakov 			NVolSetErrors(vol);
24552d86829bSAnton Altaparmakov 		} else /* if (success) */ {
24562d86829bSAnton Altaparmakov 			if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
24572d86829bSAnton Altaparmakov 					a->data.non_resident.
24582d86829bSAnton Altaparmakov 					mapping_pairs_offset), attr_len -
24592d86829bSAnton Altaparmakov 					le16_to_cpu(a->data.non_resident.
24602d86829bSAnton Altaparmakov 					mapping_pairs_offset), rl2, ll, -1,
24612d86829bSAnton Altaparmakov 					NULL)) {
24622d86829bSAnton Altaparmakov 				ntfs_error(vol->sb, "Failed to restore "
24632d86829bSAnton Altaparmakov 						"mapping pairs array in error "
24642d86829bSAnton Altaparmakov 						"code path.  Run chkdsk to "
24652d86829bSAnton Altaparmakov 						"recover.");
24662d86829bSAnton Altaparmakov 				NVolSetErrors(vol);
24672d86829bSAnton Altaparmakov 			}
24682d86829bSAnton Altaparmakov 			flush_dcache_mft_record_page(ctx->ntfs_ino);
24692d86829bSAnton Altaparmakov 			mark_mft_record_dirty(ctx->ntfs_ino);
24702d86829bSAnton Altaparmakov 		}
24712d86829bSAnton Altaparmakov 	}
24722d86829bSAnton Altaparmakov err_out:
24732d86829bSAnton Altaparmakov 	if (ctx)
24742d86829bSAnton Altaparmakov 		ntfs_attr_put_search_ctx(ctx);
24752d86829bSAnton Altaparmakov 	if (m)
24762d86829bSAnton Altaparmakov 		unmap_mft_record(base_ni);
24772d86829bSAnton Altaparmakov 	up_write(&ni->runlist.lock);
24782d86829bSAnton Altaparmakov conv_err_out:
24792d86829bSAnton Altaparmakov 	ntfs_debug("Failed.  Returning error code %i.", err);
24802d86829bSAnton Altaparmakov 	return err;
24812d86829bSAnton Altaparmakov }
24822d86829bSAnton Altaparmakov 
24832d86829bSAnton Altaparmakov /**
24841da177e4SLinus Torvalds  * ntfs_attr_set - fill (a part of) an attribute with a byte
24851da177e4SLinus Torvalds  * @ni:		ntfs inode describing the attribute to fill
24861da177e4SLinus Torvalds  * @ofs:	offset inside the attribute at which to start to fill
24871da177e4SLinus Torvalds  * @cnt:	number of bytes to fill
24881da177e4SLinus Torvalds  * @val:	the unsigned 8-bit value with which to fill the attribute
24891da177e4SLinus Torvalds  *
24901da177e4SLinus Torvalds  * Fill @cnt bytes of the attribute described by the ntfs inode @ni starting at
24911da177e4SLinus Torvalds  * byte offset @ofs inside the attribute with the constant byte @val.
24921da177e4SLinus Torvalds  *
24931da177e4SLinus Torvalds  * This function is effectively like memset() applied to an ntfs attribute.
2494*253f3137SDeming Wang  * Note this function actually only operates on the page cache pages belonging
2495da28438cSAnton Altaparmakov  * to the ntfs attribute and it marks them dirty after doing the memset().
2496da28438cSAnton Altaparmakov  * Thus it relies on the vm dirty page write code paths to cause the modified
2497da28438cSAnton Altaparmakov  * pages to be written to the mft record/disk.
24981da177e4SLinus Torvalds  *
24991da177e4SLinus Torvalds  * Return 0 on success and -errno on error.  An error code of -ESPIPE means
25001da177e4SLinus Torvalds  * that @ofs + @cnt were outside the end of the attribute and no write was
25011da177e4SLinus Torvalds  * performed.
25021da177e4SLinus Torvalds  */
ntfs_attr_set(ntfs_inode * ni,const s64 ofs,const s64 cnt,const u8 val)25031da177e4SLinus Torvalds int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
25041da177e4SLinus Torvalds {
25051da177e4SLinus Torvalds 	ntfs_volume *vol = ni->vol;
25061da177e4SLinus Torvalds 	struct address_space *mapping;
25071da177e4SLinus Torvalds 	struct page *page;
25081da177e4SLinus Torvalds 	u8 *kaddr;
25091da177e4SLinus Torvalds 	pgoff_t idx, end;
2510bfab36e8SAnton Altaparmakov 	unsigned start_ofs, end_ofs, size;
25111da177e4SLinus Torvalds 
25121da177e4SLinus Torvalds 	ntfs_debug("Entering for ofs 0x%llx, cnt 0x%llx, val 0x%hx.",
25131da177e4SLinus Torvalds 			(long long)ofs, (long long)cnt, val);
25141da177e4SLinus Torvalds 	BUG_ON(ofs < 0);
25151da177e4SLinus Torvalds 	BUG_ON(cnt < 0);
25161da177e4SLinus Torvalds 	if (!cnt)
25171da177e4SLinus Torvalds 		goto done;
2518807c453dSAnton Altaparmakov 	/*
2519807c453dSAnton Altaparmakov 	 * FIXME: Compressed and encrypted attributes are not supported when
2520807c453dSAnton Altaparmakov 	 * writing and we should never have gotten here for them.
2521807c453dSAnton Altaparmakov 	 */
2522807c453dSAnton Altaparmakov 	BUG_ON(NInoCompressed(ni));
2523807c453dSAnton Altaparmakov 	BUG_ON(NInoEncrypted(ni));
25241da177e4SLinus Torvalds 	mapping = VFS_I(ni)->i_mapping;
25251da177e4SLinus Torvalds 	/* Work out the starting index and page offset. */
252609cbfeafSKirill A. Shutemov 	idx = ofs >> PAGE_SHIFT;
252709cbfeafSKirill A. Shutemov 	start_ofs = ofs & ~PAGE_MASK;
25281da177e4SLinus Torvalds 	/* Work out the ending index and page offset. */
25291da177e4SLinus Torvalds 	end = ofs + cnt;
253009cbfeafSKirill A. Shutemov 	end_ofs = end & ~PAGE_MASK;
25311da177e4SLinus Torvalds 	/* If the end is outside the inode size return -ESPIPE. */
2532da28438cSAnton Altaparmakov 	if (unlikely(end > i_size_read(VFS_I(ni)))) {
25331da177e4SLinus Torvalds 		ntfs_error(vol->sb, "Request exceeds end of attribute.");
25341da177e4SLinus Torvalds 		return -ESPIPE;
25351da177e4SLinus Torvalds 	}
253609cbfeafSKirill A. Shutemov 	end >>= PAGE_SHIFT;
25371da177e4SLinus Torvalds 	/* If there is a first partial page, need to do it the slow way. */
25381da177e4SLinus Torvalds 	if (start_ofs) {
2539090d2b18SPekka Enberg 		page = read_mapping_page(mapping, idx, NULL);
25401da177e4SLinus Torvalds 		if (IS_ERR(page)) {
25411da177e4SLinus Torvalds 			ntfs_error(vol->sb, "Failed to read first partial "
25426fe6900eSNick Piggin 					"page (error, index 0x%lx).", idx);
25431da177e4SLinus Torvalds 			return PTR_ERR(page);
25441da177e4SLinus Torvalds 		}
25451da177e4SLinus Torvalds 		/*
25461da177e4SLinus Torvalds 		 * If the last page is the same as the first page, need to
25471da177e4SLinus Torvalds 		 * limit the write to the end offset.
25481da177e4SLinus Torvalds 		 */
254909cbfeafSKirill A. Shutemov 		size = PAGE_SIZE;
25501da177e4SLinus Torvalds 		if (idx == end)
25511da177e4SLinus Torvalds 			size = end_ofs;
2552a3ac1414SCong Wang 		kaddr = kmap_atomic(page);
25531da177e4SLinus Torvalds 		memset(kaddr + start_ofs, val, size - start_ofs);
25541da177e4SLinus Torvalds 		flush_dcache_page(page);
2555a3ac1414SCong Wang 		kunmap_atomic(kaddr);
25561da177e4SLinus Torvalds 		set_page_dirty(page);
255709cbfeafSKirill A. Shutemov 		put_page(page);
2558bfab36e8SAnton Altaparmakov 		balance_dirty_pages_ratelimited(mapping);
2559bfab36e8SAnton Altaparmakov 		cond_resched();
25601da177e4SLinus Torvalds 		if (idx == end)
25611da177e4SLinus Torvalds 			goto done;
25621da177e4SLinus Torvalds 		idx++;
25631da177e4SLinus Torvalds 	}
25641da177e4SLinus Torvalds 	/* Do the whole pages the fast way. */
25651da177e4SLinus Torvalds 	for (; idx < end; idx++) {
25661da177e4SLinus Torvalds 		/* Find or create the current page.  (The page is locked.) */
25671da177e4SLinus Torvalds 		page = grab_cache_page(mapping, idx);
25681da177e4SLinus Torvalds 		if (unlikely(!page)) {
25691da177e4SLinus Torvalds 			ntfs_error(vol->sb, "Insufficient memory to grab "
25701da177e4SLinus Torvalds 					"page (index 0x%lx).", idx);
25711da177e4SLinus Torvalds 			return -ENOMEM;
25721da177e4SLinus Torvalds 		}
2573a3ac1414SCong Wang 		kaddr = kmap_atomic(page);
257409cbfeafSKirill A. Shutemov 		memset(kaddr, val, PAGE_SIZE);
25751da177e4SLinus Torvalds 		flush_dcache_page(page);
2576a3ac1414SCong Wang 		kunmap_atomic(kaddr);
25771da177e4SLinus Torvalds 		/*
25781da177e4SLinus Torvalds 		 * If the page has buffers, mark them uptodate since buffer
25791da177e4SLinus Torvalds 		 * state and not page state is definitive in 2.6 kernels.
25801da177e4SLinus Torvalds 		 */
25811da177e4SLinus Torvalds 		if (page_has_buffers(page)) {
25821da177e4SLinus Torvalds 			struct buffer_head *bh, *head;
25831da177e4SLinus Torvalds 
25841da177e4SLinus Torvalds 			bh = head = page_buffers(page);
25851da177e4SLinus Torvalds 			do {
25861da177e4SLinus Torvalds 				set_buffer_uptodate(bh);
25871da177e4SLinus Torvalds 			} while ((bh = bh->b_this_page) != head);
25881da177e4SLinus Torvalds 		}
25891da177e4SLinus Torvalds 		/* Now that buffers are uptodate, set the page uptodate, too. */
25901da177e4SLinus Torvalds 		SetPageUptodate(page);
25911da177e4SLinus Torvalds 		/*
25921da177e4SLinus Torvalds 		 * Set the page and all its buffers dirty and mark the inode
25931da177e4SLinus Torvalds 		 * dirty, too.  The VM will write the page later on.
25941da177e4SLinus Torvalds 		 */
25951da177e4SLinus Torvalds 		set_page_dirty(page);
25961da177e4SLinus Torvalds 		/* Finally unlock and release the page. */
25971da177e4SLinus Torvalds 		unlock_page(page);
259809cbfeafSKirill A. Shutemov 		put_page(page);
259929b89905SAnton Altaparmakov 		balance_dirty_pages_ratelimited(mapping);
260029b89905SAnton Altaparmakov 		cond_resched();
26011da177e4SLinus Torvalds 	}
26021da177e4SLinus Torvalds 	/* If there is a last partial page, need to do it the slow way. */
26031da177e4SLinus Torvalds 	if (end_ofs) {
2604090d2b18SPekka Enberg 		page = read_mapping_page(mapping, idx, NULL);
26051da177e4SLinus Torvalds 		if (IS_ERR(page)) {
26061da177e4SLinus Torvalds 			ntfs_error(vol->sb, "Failed to read last partial page "
26076fe6900eSNick Piggin 					"(error, index 0x%lx).", idx);
26081da177e4SLinus Torvalds 			return PTR_ERR(page);
26091da177e4SLinus Torvalds 		}
2610a3ac1414SCong Wang 		kaddr = kmap_atomic(page);
26111da177e4SLinus Torvalds 		memset(kaddr, val, end_ofs);
26121da177e4SLinus Torvalds 		flush_dcache_page(page);
2613a3ac1414SCong Wang 		kunmap_atomic(kaddr);
26141da177e4SLinus Torvalds 		set_page_dirty(page);
261509cbfeafSKirill A. Shutemov 		put_page(page);
2616bfab36e8SAnton Altaparmakov 		balance_dirty_pages_ratelimited(mapping);
2617bfab36e8SAnton Altaparmakov 		cond_resched();
26181da177e4SLinus Torvalds 	}
26191da177e4SLinus Torvalds done:
26201da177e4SLinus Torvalds 	ntfs_debug("Done.");
26211da177e4SLinus Torvalds 	return 0;
26221da177e4SLinus Torvalds }
262353d59aadSAnton Altaparmakov 
262453d59aadSAnton Altaparmakov #endif /* NTFS_RW */
2625