~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/ntfs/logfile.c

Version: ~ [ linux-5.7-rc7 ] ~ [ linux-5.6.14 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.42 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.124 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.181 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.224 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.224 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.84 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
  3  *
  4  * Copyright (c) 2002-2007 Anton Altaparmakov
  5  *
  6  * This program/include file is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU General Public License as published
  8  * by the Free Software Foundation; either version 2 of the License, or
  9  * (at your option) any later version.
 10  *
 11  * This program/include file is distributed in the hope that it will be
 12  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  * GNU General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU General Public License
 17  * along with this program (in the main directory of the Linux-NTFS
 18  * distribution in the file COPYING); if not, write to the Free Software
 19  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 20  */
 21 
 22 #ifdef NTFS_RW
 23 
 24 #include <linux/types.h>
 25 #include <linux/fs.h>
 26 #include <linux/highmem.h>
 27 #include <linux/buffer_head.h>
 28 #include <linux/bitops.h>
 29 #include <linux/log2.h>
 30 #include <linux/bio.h>
 31 
 32 #include "attrib.h"
 33 #include "aops.h"
 34 #include "debug.h"
 35 #include "logfile.h"
 36 #include "malloc.h"
 37 #include "volume.h"
 38 #include "ntfs.h"
 39 
 40 /**
 41  * ntfs_check_restart_page_header - check the page header for consistency
 42  * @vi:         $LogFile inode to which the restart page header belongs
 43  * @rp:         restart page header to check
 44  * @pos:        position in @vi at which the restart page header resides
 45  *
 46  * Check the restart page header @rp for consistency and return 'true' if it is
 47  * consistent and 'false' otherwise.
 48  *
 49  * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
 50  * require the full restart page.
 51  */
 52 static bool ntfs_check_restart_page_header(struct inode *vi,
 53                 RESTART_PAGE_HEADER *rp, s64 pos)
 54 {
 55         u32 logfile_system_page_size, logfile_log_page_size;
 56         u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
 57         bool have_usa = true;
 58 
 59         ntfs_debug("Entering.");
 60         /*
 61          * If the system or log page sizes are smaller than the ntfs block size
 62          * or either is not a power of 2 we cannot handle this log file.
 63          */
 64         logfile_system_page_size = le32_to_cpu(rp->system_page_size);
 65         logfile_log_page_size = le32_to_cpu(rp->log_page_size);
 66         if (logfile_system_page_size < NTFS_BLOCK_SIZE ||
 67                         logfile_log_page_size < NTFS_BLOCK_SIZE ||
 68                         logfile_system_page_size &
 69                         (logfile_system_page_size - 1) ||
 70                         !is_power_of_2(logfile_log_page_size)) {
 71                 ntfs_error(vi->i_sb, "$LogFile uses unsupported page size.");
 72                 return false;
 73         }
 74         /*
 75          * We must be either at !pos (1st restart page) or at pos = system page
 76          * size (2nd restart page).
 77          */
 78         if (pos && pos != logfile_system_page_size) {
 79                 ntfs_error(vi->i_sb, "Found restart area in incorrect "
 80                                 "position in $LogFile.");
 81                 return false;
 82         }
 83         /* We only know how to handle version 1.1. */
 84         if (sle16_to_cpu(rp->major_ver) != 1 ||
 85                         sle16_to_cpu(rp->minor_ver) != 1) {
 86                 ntfs_error(vi->i_sb, "$LogFile version %i.%i is not "
 87                                 "supported.  (This driver supports version "
 88                                 "1.1 only.)", (int)sle16_to_cpu(rp->major_ver),
 89                                 (int)sle16_to_cpu(rp->minor_ver));
 90                 return false;
 91         }
 92         /*
 93          * If chkdsk has been run the restart page may not be protected by an
 94          * update sequence array.
 95          */
 96         if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
 97                 have_usa = false;
 98                 goto skip_usa_checks;
 99         }
100         /* Verify the size of the update sequence array. */
101         usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
102         if (usa_count != le16_to_cpu(rp->usa_count)) {
103                 ntfs_error(vi->i_sb, "$LogFile restart page specifies "
104                                 "inconsistent update sequence array count.");
105                 return false;
106         }
107         /* Verify the position of the update sequence array. */
108         usa_ofs = le16_to_cpu(rp->usa_ofs);
109         usa_end = usa_ofs + usa_count * sizeof(u16);
110         if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
111                         usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
112                 ntfs_error(vi->i_sb, "$LogFile restart page specifies "
113                                 "inconsistent update sequence array offset.");
114                 return false;
115         }
116 skip_usa_checks:
117         /*
118          * Verify the position of the restart area.  It must be:
119          *      - aligned to 8-byte boundary,
120          *      - after the update sequence array, and
121          *      - within the system page size.
122          */
123         ra_ofs = le16_to_cpu(rp->restart_area_offset);
124         if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
125                         ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
126                         ra_ofs > logfile_system_page_size) {
127                 ntfs_error(vi->i_sb, "$LogFile restart page specifies "
128                                 "inconsistent restart area offset.");
129                 return false;
130         }
131         /*
132          * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
133          * set.
134          */
135         if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
136                 ntfs_error(vi->i_sb, "$LogFile restart page is not modified "
137                                 "by chkdsk but a chkdsk LSN is specified.");
138                 return false;
139         }
140         ntfs_debug("Done.");
141         return true;
142 }
143 
144 /**
145  * ntfs_check_restart_area - check the restart area for consistency
146  * @vi:         $LogFile inode to which the restart page belongs
147  * @rp:         restart page whose restart area to check
148  *
149  * Check the restart area of the restart page @rp for consistency and return
150  * 'true' if it is consistent and 'false' otherwise.
151  *
152  * This function assumes that the restart page header has already been
153  * consistency checked.
154  *
155  * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
156  * require the full restart page.
157  */
158 static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
159 {
160         u64 file_size;
161         RESTART_AREA *ra;
162         u16 ra_ofs, ra_len, ca_ofs;
163         u8 fs_bits;
164 
165         ntfs_debug("Entering.");
166         ra_ofs = le16_to_cpu(rp->restart_area_offset);
167         ra = (RESTART_AREA*)((u8*)rp + ra_ofs);
168         /*
169          * Everything before ra->file_size must be before the first word
170          * protected by an update sequence number.  This ensures that it is
171          * safe to access ra->client_array_offset.
172          */
173         if (ra_ofs + offsetof(RESTART_AREA, file_size) >
174                         NTFS_BLOCK_SIZE - sizeof(u16)) {
175                 ntfs_error(vi->i_sb, "$LogFile restart area specifies "
176                                 "inconsistent file offset.");
177                 return false;
178         }
179         /*
180          * Now that we can access ra->client_array_offset, make sure everything
181          * up to the log client array is before the first word protected by an
182          * update sequence number.  This ensures we can access all of the
183          * restart area elements safely.  Also, the client array offset must be
184          * aligned to an 8-byte boundary.
185          */
186         ca_ofs = le16_to_cpu(ra->client_array_offset);
187         if (((ca_ofs + 7) & ~7) != ca_ofs ||
188                         ra_ofs + ca_ofs > NTFS_BLOCK_SIZE - sizeof(u16)) {
189                 ntfs_error(vi->i_sb, "$LogFile restart area specifies "
190                                 "inconsistent client array offset.");
191                 return false;
192         }
193         /*
194          * The restart area must end within the system page size both when
195          * calculated manually and as specified by ra->restart_area_length.
196          * Also, the calculated length must not exceed the specified length.
197          */
198         ra_len = ca_ofs + le16_to_cpu(ra->log_clients) *
199                         sizeof(LOG_CLIENT_RECORD);
200         if (ra_ofs + ra_len > le32_to_cpu(rp->system_page_size) ||
201                         ra_ofs + le16_to_cpu(ra->restart_area_length) >
202                         le32_to_cpu(rp->system_page_size) ||
203                         ra_len > le16_to_cpu(ra->restart_area_length)) {
204                 ntfs_error(vi->i_sb, "$LogFile restart area is out of bounds "
205                                 "of the system page size specified by the "
206                                 "restart page header and/or the specified "
207                                 "restart area length is inconsistent.");
208                 return false;
209         }
210         /*
211          * The ra->client_free_list and ra->client_in_use_list must be either
212          * LOGFILE_NO_CLIENT or less than ra->log_clients or they are
213          * overflowing the client array.
214          */
215         if ((ra->client_free_list != LOGFILE_NO_CLIENT &&
216                         le16_to_cpu(ra->client_free_list) >=
217                         le16_to_cpu(ra->log_clients)) ||
218                         (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
219                         le16_to_cpu(ra->client_in_use_list) >=
220                         le16_to_cpu(ra->log_clients))) {
221                 ntfs_error(vi->i_sb, "$LogFile restart area specifies "
222                                 "overflowing client free and/or in use lists.");
223                 return false;
224         }
225         /*
226          * Check ra->seq_number_bits against ra->file_size for consistency.
227          * We cannot just use ffs() because the file size is not a power of 2.
228          */
229         file_size = (u64)sle64_to_cpu(ra->file_size);
230         fs_bits = 0;
231         while (file_size) {
232                 file_size >>= 1;
233                 fs_bits++;
234         }
235         if (le32_to_cpu(ra->seq_number_bits) != 67 - fs_bits) {
236                 ntfs_error(vi->i_sb, "$LogFile restart area specifies "
237                                 "inconsistent sequence number bits.");
238                 return false;
239         }
240         /* The log record header length must be a multiple of 8. */
241         if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
242                         le16_to_cpu(ra->log_record_header_length)) {
243                 ntfs_error(vi->i_sb, "$LogFile restart area specifies "
244                                 "inconsistent log record header length.");
245                 return false;
246         }
247         /* Dito for the log page data offset. */
248         if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
249                         le16_to_cpu(ra->log_page_data_offset)) {
250                 ntfs_error(vi->i_sb, "$LogFile restart area specifies "
251                                 "inconsistent log page data offset.");
252                 return false;
253         }
254         ntfs_debug("Done.");
255         return true;
256 }
257 
258 /**
259  * ntfs_check_log_client_array - check the log client array for consistency
260  * @vi:         $LogFile inode to which the restart page belongs
261  * @rp:         restart page whose log client array to check
262  *
263  * Check the log client array of the restart page @rp for consistency and
264  * return 'true' if it is consistent and 'false' otherwise.
265  *
266  * This function assumes that the restart page header and the restart area have
267  * already been consistency checked.
268  *
269  * Unlike ntfs_check_restart_page_header() and ntfs_check_restart_area(), this
270  * function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
271  * restart page and the page must be multi sector transfer deprotected.
272  */
273 static bool ntfs_check_log_client_array(struct inode *vi,
274                 RESTART_PAGE_HEADER *rp)
275 {
276         RESTART_AREA *ra;
277         LOG_CLIENT_RECORD *ca, *cr;
278         u16 nr_clients, idx;
279         bool in_free_list, idx_is_first;
280 
281         ntfs_debug("Entering.");
282         ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
283         ca = (LOG_CLIENT_RECORD*)((u8*)ra +
284                         le16_to_cpu(ra->client_array_offset));
285         /*
286          * Check the ra->client_free_list first and then check the
287          * ra->client_in_use_list.  Check each of the log client records in
288          * each of the lists and check that the array does not overflow the
289          * ra->log_clients value.  Also keep track of the number of records
290          * visited as there cannot be more than ra->log_clients records and
291          * that way we detect eventual loops in within a list.
292          */
293         nr_clients = le16_to_cpu(ra->log_clients);
294         idx = le16_to_cpu(ra->client_free_list);
295         in_free_list = true;
296 check_list:
297         for (idx_is_first = true; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
298                         idx = le16_to_cpu(cr->next_client)) {
299                 if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
300                         goto err_out;
301                 /* Set @cr to the current log client record. */
302                 cr = ca + idx;
303                 /* The first log client record must not have a prev_client. */
304                 if (idx_is_first) {
305                         if (cr->prev_client != LOGFILE_NO_CLIENT)
306                                 goto err_out;
307                         idx_is_first = false;
308                 }
309         }
310         /* Switch to and check the in use list if we just did the free list. */
311         if (in_free_list) {
312                 in_free_list = false;
313                 idx = le16_to_cpu(ra->client_in_use_list);
314                 goto check_list;
315         }
316         ntfs_debug("Done.");
317         return true;
318 err_out:
319         ntfs_error(vi->i_sb, "$LogFile log client array is corrupt.");
320         return false;
321 }
322 
323 /**
324  * ntfs_check_and_load_restart_page - check the restart page for consistency
325  * @vi:         $LogFile inode to which the restart page belongs
326  * @rp:         restart page to check
327  * @pos:        position in @vi at which the restart page resides
328  * @wrp:        [OUT] copy of the multi sector transfer deprotected restart page
329  * @lsn:        [OUT] set to the current logfile lsn on success
330  *
331  * Check the restart page @rp for consistency and return 0 if it is consistent
332  * and -errno otherwise.  The restart page may have been modified by chkdsk in
333  * which case its magic is CHKD instead of RSTR.
334  *
335  * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
336  * require the full restart page.
337  *
338  * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a
339  * copy of the complete multi sector transfer deprotected page.  On failure,
340  * *@wrp is undefined.
341  *
342  * Simillarly, if @lsn is not NULL, on success *@lsn will be set to the current
343  * logfile lsn according to this restart page.  On failure, *@lsn is undefined.
344  *
345  * The following error codes are defined:
346  *      -EINVAL - The restart page is inconsistent.
347  *      -ENOMEM - Not enough memory to load the restart page.
348  *      -EIO    - Failed to reading from $LogFile.
349  */
350 static int ntfs_check_and_load_restart_page(struct inode *vi,
351                 RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
352                 LSN *lsn)
353 {
354         RESTART_AREA *ra;
355         RESTART_PAGE_HEADER *trp;
356         int size, err;
357 
358         ntfs_debug("Entering.");
359         /* Check the restart page header for consistency. */
360         if (!ntfs_check_restart_page_header(vi, rp, pos)) {
361                 /* Error output already done inside the function. */
362                 return -EINVAL;
363         }
364         /* Check the restart area for consistency. */
365         if (!ntfs_check_restart_area(vi, rp)) {
366                 /* Error output already done inside the function. */
367                 return -EINVAL;
368         }
369         ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
370         /*
371          * Allocate a buffer to store the whole restart page so we can multi
372          * sector transfer deprotect it.
373          */
374         trp = ntfs_malloc_nofs(le32_to_cpu(rp->system_page_size));
375         if (!trp) {
376                 ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile "
377                                 "restart page buffer.");
378                 return -ENOMEM;
379         }
380         /*
381          * Read the whole of the restart page into the buffer.  If it fits
382          * completely inside @rp, just copy it from there.  Otherwise map all
383          * the required pages and copy the data from them.
384          */
385         size = PAGE_SIZE - (pos & ~PAGE_MASK);
386         if (size >= le32_to_cpu(rp->system_page_size)) {
387                 memcpy(trp, rp, le32_to_cpu(rp->system_page_size));
388         } else {
389                 pgoff_t idx;
390                 struct page *page;
391                 int have_read, to_read;
392 
393                 /* First copy what we already have in @rp. */
394                 memcpy(trp, rp, size);
395                 /* Copy the remaining data one page at a time. */
396                 have_read = size;
397                 to_read = le32_to_cpu(rp->system_page_size) - size;
398                 idx = (pos + size) >> PAGE_SHIFT;
399                 BUG_ON((pos + size) & ~PAGE_MASK);
400                 do {
401                         page = ntfs_map_page(vi->i_mapping, idx);
402                         if (IS_ERR(page)) {
403                                 ntfs_error(vi->i_sb, "Error mapping $LogFile "
404                                                 "page (index %lu).", idx);
405                                 err = PTR_ERR(page);
406                                 if (err != -EIO && err != -ENOMEM)
407                                         err = -EIO;
408                                 goto err_out;
409                         }
410                         size = min_t(int, to_read, PAGE_SIZE);
411                         memcpy((u8*)trp + have_read, page_address(page), size);
412                         ntfs_unmap_page(page);
413                         have_read += size;
414                         to_read -= size;
415                         idx++;
416                 } while (to_read > 0);
417         }
418         /*
419          * Perform the multi sector transfer deprotection on the buffer if the
420          * restart page is protected.
421          */
422         if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
423                         && post_read_mst_fixup((NTFS_RECORD*)trp,
424                         le32_to_cpu(rp->system_page_size))) {
425                 /*
426                  * A multi sector tranfer error was detected.  We only need to
427                  * abort if the restart page contents exceed the multi sector
428                  * transfer fixup of the first sector.
429                  */
430                 if (le16_to_cpu(rp->restart_area_offset) +
431                                 le16_to_cpu(ra->restart_area_length) >
432                                 NTFS_BLOCK_SIZE - sizeof(u16)) {
433                         ntfs_error(vi->i_sb, "Multi sector transfer error "
434                                         "detected in $LogFile restart page.");
435                         err = -EINVAL;
436                         goto err_out;
437                 }
438         }
439         /*
440          * If the restart page is modified by chkdsk or there are no active
441          * logfile clients, the logfile is consistent.  Otherwise, need to
442          * check the log client records for consistency, too.
443          */
444         err = 0;
445         if (ntfs_is_rstr_record(rp->magic) &&
446                         ra->client_in_use_list != LOGFILE_NO_CLIENT) {
447                 if (!ntfs_check_log_client_array(vi, trp)) {
448                         err = -EINVAL;
449                         goto err_out;
450                 }
451         }
452         if (lsn) {
453                 if (ntfs_is_rstr_record(rp->magic))
454                         *lsn = sle64_to_cpu(ra->current_lsn);
455                 else /* if (ntfs_is_chkd_record(rp->magic)) */
456                         *lsn = sle64_to_cpu(rp->chkdsk_lsn);
457         }
458         ntfs_debug("Done.");
459         if (wrp)
460                 *wrp = trp;
461         else {
462 err_out:
463                 ntfs_free(trp);
464         }
465         return err;
466 }
467 
468 /**
469  * ntfs_check_logfile - check the journal for consistency
470  * @log_vi:     struct inode of loaded journal $LogFile to check
471  * @rp:         [OUT] on success this is a copy of the current restart page
472  *
473  * Check the $LogFile journal for consistency and return 'true' if it is
474  * consistent and 'false' if not.  On success, the current restart page is
475  * returned in *@rp.  Caller must call ntfs_free(*@rp) when finished with it.
476  *
477  * At present we only check the two restart pages and ignore the log record
478  * pages.
479  *
480  * Note that the MstProtected flag is not set on the $LogFile inode and hence
481  * when reading pages they are not deprotected.  This is because we do not know
482  * if the $LogFile was created on a system with a different page size to ours
483  * yet and mst deprotection would fail if our page size is smaller.
484  */
485 bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
486 {
487         s64 size, pos;
488         LSN rstr1_lsn, rstr2_lsn;
489         ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
490         struct address_space *mapping = log_vi->i_mapping;
491         struct page *page = NULL;
492         u8 *kaddr = NULL;
493         RESTART_PAGE_HEADER *rstr1_ph = NULL;
494         RESTART_PAGE_HEADER *rstr2_ph = NULL;
495         int log_page_size, log_page_mask, err;
496         bool logfile_is_empty = true;
497         u8 log_page_bits;
498 
499         ntfs_debug("Entering.");
500         /* An empty $LogFile must have been clean before it got emptied. */
501         if (NVolLogFileEmpty(vol))
502                 goto is_empty;
503         size = i_size_read(log_vi);
504         /* Make sure the file doesn't exceed the maximum allowed size. */
505         if (size > MaxLogFileSize)
506                 size = MaxLogFileSize;
507         /*
508          * Truncate size to a multiple of the page cache size or the default
509          * log page size if the page cache size is between the default log page
510          * log page size if the page cache size is between the default log page
511          * size and twice that.
512          */
513         if (PAGE_SIZE >= DefaultLogPageSize && PAGE_SIZE <=
514                         DefaultLogPageSize * 2)
515                 log_page_size = DefaultLogPageSize;
516         else
517                 log_page_size = PAGE_SIZE;
518         log_page_mask = log_page_size - 1;
519         /*
520          * Use ntfs_ffs() instead of ffs() to enable the compiler to
521          * optimize log_page_size and log_page_bits into constants.
522          */
523         log_page_bits = ntfs_ffs(log_page_size) - 1;
524         size &= ~(s64)(log_page_size - 1);
525         /*
526          * Ensure the log file is big enough to store at least the two restart
527          * pages and the minimum number of log record pages.
528          */
529         if (size < log_page_size * 2 || (size - log_page_size * 2) >>
530                         log_page_bits < MinLogRecordPages) {
531                 ntfs_error(vol->sb, "$LogFile is too small.");
532                 return false;
533         }
534         /*
535          * Read through the file looking for a restart page.  Since the restart
536          * page header is at the beginning of a page we only need to search at
537          * what could be the beginning of a page (for each page size) rather
538          * than scanning the whole file byte by byte.  If all potential places
539          * contain empty and uninitialzed records, the log file can be assumed
540          * to be empty.
541          */
542         for (pos = 0; pos < size; pos <<= 1) {
543                 pgoff_t idx = pos >> PAGE_SHIFT;
544                 if (!page || page->index != idx) {
545                         if (page)
546                                 ntfs_unmap_page(page);
547                         page = ntfs_map_page(mapping, idx);
548                         if (IS_ERR(page)) {
549                                 ntfs_error(vol->sb, "Error mapping $LogFile "
550                                                 "page (index %lu).", idx);
551                                 goto err_out;
552                         }
553                 }
554                 kaddr = (u8*)page_address(page) + (pos & ~PAGE_MASK);
555                 /*
556                  * A non-empty block means the logfile is not empty while an
557                  * empty block after a non-empty block has been encountered
558                  * means we are done.
559                  */
560                 if (!ntfs_is_empty_recordp((le32*)kaddr))
561                         logfile_is_empty = false;
562                 else if (!logfile_is_empty)
563                         break;
564                 /*
565                  * A log record page means there cannot be a restart page after
566                  * this so no need to continue searching.
567                  */
568                 if (ntfs_is_rcrd_recordp((le32*)kaddr))
569                         break;
570                 /* If not a (modified by chkdsk) restart page, continue. */
571                 if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
572                                 !ntfs_is_chkd_recordp((le32*)kaddr)) {
573                         if (!pos)
574                                 pos = NTFS_BLOCK_SIZE >> 1;
575                         continue;
576                 }
577                 /*
578                  * Check the (modified by chkdsk) restart page for consistency
579                  * and get a copy of the complete multi sector transfer
580                  * deprotected restart page.
581                  */
582                 err = ntfs_check_and_load_restart_page(log_vi,
583                                 (RESTART_PAGE_HEADER*)kaddr, pos,
584                                 !rstr1_ph ? &rstr1_ph : &rstr2_ph,
585                                 !rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
586                 if (!err) {
587                         /*
588                          * If we have now found the first (modified by chkdsk)
589                          * restart page, continue looking for the second one.
590                          */
591                         if (!pos) {
592                                 pos = NTFS_BLOCK_SIZE >> 1;
593                                 continue;
594                         }
595                         /*
596                          * We have now found the second (modified by chkdsk)
597                          * restart page, so we can stop looking.
598                          */
599                         break;
600                 }
601                 /*
602                  * Error output already done inside the function.  Note, we do
603                  * not abort if the restart page was invalid as we might still
604                  * find a valid one further in the file.
605                  */
606                 if (err != -EINVAL) {
607                         ntfs_unmap_page(page);
608                         goto err_out;
609                 }
610                 /* Continue looking. */
611                 if (!pos)
612                         pos = NTFS_BLOCK_SIZE >> 1;
613         }
614         if (page)
615                 ntfs_unmap_page(page);
616         if (logfile_is_empty) {
617                 NVolSetLogFileEmpty(vol);
618 is_empty:
619                 ntfs_debug("Done.  ($LogFile is empty.)");
620                 return true;
621         }
622         if (!rstr1_ph) {
623                 BUG_ON(rstr2_ph);
624                 ntfs_error(vol->sb, "Did not find any restart pages in "
625                                 "$LogFile and it was not empty.");
626                 return false;
627         }
628         /* If both restart pages were found, use the more recent one. */
629         if (rstr2_ph) {
630                 /*
631                  * If the second restart area is more recent, switch to it.
632                  * Otherwise just throw it away.
633                  */
634                 if (rstr2_lsn > rstr1_lsn) {
635                         ntfs_debug("Using second restart page as it is more "
636                                         "recent.");
637                         ntfs_free(rstr1_ph);
638                         rstr1_ph = rstr2_ph;
639                         /* rstr1_lsn = rstr2_lsn; */
640                 } else {
641                         ntfs_debug("Using first restart page as it is more "
642                                         "recent.");
643                         ntfs_free(rstr2_ph);
644                 }
645                 rstr2_ph = NULL;
646         }
647         /* All consistency checks passed. */
648         if (rp)
649                 *rp = rstr1_ph;
650         else
651                 ntfs_free(rstr1_ph);
652         ntfs_debug("Done.");
653         return true;
654 err_out:
655         if (rstr1_ph)
656                 ntfs_free(rstr1_ph);
657         return false;
658 }
659 
660 /**
661  * ntfs_is_logfile_clean - check in the journal if the volume is clean
662  * @log_vi:     struct inode of loaded journal $LogFile to check
663  * @rp:         copy of the current restart page
664  *
665  * Analyze the $LogFile journal and return 'true' if it indicates the volume was
666  * shutdown cleanly and 'false' if not.
667  *
668  * At present we only look at the two restart pages and ignore the log record
669  * pages.  This is a little bit crude in that there will be a very small number
670  * of cases where we think that a volume is dirty when in fact it is clean.
671  * This should only affect volumes that have not been shutdown cleanly but did
672  * not have any pending, non-check-pointed i/o, i.e. they were completely idle
673  * at least for the five seconds preceding the unclean shutdown.
674  *
675  * This function assumes that the $LogFile journal has already been consistency
676  * checked by a call to ntfs_check_logfile() and in particular if the $LogFile
677  * is empty this function requires that NVolLogFileEmpty() is true otherwise an
678  * empty volume will be reported as dirty.
679  */
680 bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
681 {
682         ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
683         RESTART_AREA *ra;
684 
685         ntfs_debug("Entering.");
686         /* An empty $LogFile must have been clean before it got emptied. */
687         if (NVolLogFileEmpty(vol)) {
688                 ntfs_debug("Done.  ($LogFile is empty.)");
689                 return true;
690         }
691         BUG_ON(!rp);
692         if (!ntfs_is_rstr_record(rp->magic) &&
693                         !ntfs_is_chkd_record(rp->magic)) {
694                 ntfs_error(vol->sb, "Restart page buffer is invalid.  This is "
695                                 "probably a bug in that the $LogFile should "
696                                 "have been consistency checked before calling "
697                                 "this function.");
698                 return false;
699         }
700         ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
701         /*
702          * If the $LogFile has active clients, i.e. it is open, and we do not
703          * have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
704          * we assume there was an unclean shutdown.
705          */
706         if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
707                         !(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
708                 ntfs_debug("Done.  $LogFile indicates a dirty shutdown.");
709                 return false;
710         }
711         /* $LogFile indicates a clean shutdown. */
712         ntfs_debug("Done.  $LogFile indicates a clean shutdown.");
713         return true;
714 }
715 
716 /**
717  * ntfs_empty_logfile - empty the contents of the $LogFile journal
718  * @log_vi:     struct inode of loaded journal $LogFile to empty
719  *
720  * Empty the contents of the $LogFile journal @log_vi and return 'true' on
721  * success and 'false' on error.
722  *
723  * This function assumes that the $LogFile journal has already been consistency
724  * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
725  * has been used to ensure that the $LogFile is clean.
726  */
727 bool ntfs_empty_logfile(struct inode *log_vi)
728 {
729         VCN vcn, end_vcn;
730         ntfs_inode *log_ni = NTFS_I(log_vi);
731         ntfs_volume *vol = log_ni->vol;
732         struct super_block *sb = vol->sb;
733         runlist_element *rl;
734         unsigned long flags;
735         unsigned block_size, block_size_bits;
736         int err;
737         bool should_wait = true;
738 
739         ntfs_debug("Entering.");
740         if (NVolLogFileEmpty(vol)) {
741                 ntfs_debug("Done.");
742                 return true;
743         }
744         /*
745          * We cannot use ntfs_attr_set() because we may be still in the middle
746          * of a mount operation.  Thus we do the emptying by hand by first
747          * zapping the page cache pages for the $LogFile/$DATA attribute and
748          * then emptying each of the buffers in each of the clusters specified
749          * by the runlist by hand.
750          */
751         block_size = sb->s_blocksize;
752         block_size_bits = sb->s_blocksize_bits;
753         vcn = 0;
754         read_lock_irqsave(&log_ni->size_lock, flags);
755         end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >>
756                         vol->cluster_size_bits;
757         read_unlock_irqrestore(&log_ni->size_lock, flags);
758         truncate_inode_pages(log_vi->i_mapping, 0);
759         down_write(&log_ni->runlist.lock);
760         rl = log_ni->runlist.rl;
761         if (unlikely(!rl || vcn < rl->vcn || !rl->length)) {
762 map_vcn:
763                 err = ntfs_map_runlist_nolock(log_ni, vcn, NULL);
764                 if (err) {
765                         ntfs_error(sb, "Failed to map runlist fragment (error "
766                                         "%d).", -err);
767                         goto err;
768                 }
769                 rl = log_ni->runlist.rl;
770                 BUG_ON(!rl || vcn < rl->vcn || !rl->length);
771         }
772         /* Seek to the runlist element containing @vcn. */
773         while (rl->length && vcn >= rl[1].vcn)
774                 rl++;
775         do {
776                 LCN lcn;
777                 sector_t block, end_block;
778                 s64 len;
779 
780                 /*
781                  * If this run is not mapped map it now and start again as the
782                  * runlist will have been updated.
783                  */
784                 lcn = rl->lcn;
785                 if (unlikely(lcn == LCN_RL_NOT_MAPPED)) {
786                         vcn = rl->vcn;
787                         goto map_vcn;
788                 }
789                 /* If this run is not valid abort with an error. */
790                 if (unlikely(!rl->length || lcn < LCN_HOLE))
791                         goto rl_err;
792                 /* Skip holes. */
793                 if (lcn == LCN_HOLE)
794                         continue;
795                 block = lcn << vol->cluster_size_bits >> block_size_bits;
796                 len = rl->length;
797                 if (rl[1].vcn > end_vcn)
798                         len = end_vcn - rl->vcn;
799                 end_block = (lcn + len) << vol->cluster_size_bits >>
800                                 block_size_bits;
801                 /* Iterate over the blocks in the run and empty them. */
802                 do {
803                         struct buffer_head *bh;
804 
805                         /* Obtain the buffer, possibly not uptodate. */
806                         bh = sb_getblk(sb, block);
807                         BUG_ON(!bh);
808                         /* Setup buffer i/o submission. */
809                         lock_buffer(bh);
810                         bh->b_end_io = end_buffer_write_sync;
811                         get_bh(bh);
812                         /* Set the entire contents of the buffer to 0xff. */
813                         memset(bh->b_data, -1, block_size);
814                         if (!buffer_uptodate(bh))
815                                 set_buffer_uptodate(bh);
816                         if (buffer_dirty(bh))
817                                 clear_buffer_dirty(bh);
818                         /*
819                          * Submit the buffer and wait for i/o to complete but
820                          * only for the first buffer so we do not miss really
821                          * serious i/o errors.  Once the first buffer has
822                          * completed ignore errors afterwards as we can assume
823                          * that if one buffer worked all of them will work.
824                          */
825                         submit_bh(REQ_OP_WRITE, 0, bh);
826                         if (should_wait) {
827                                 should_wait = false;
828                                 wait_on_buffer(bh);
829                                 if (unlikely(!buffer_uptodate(bh)))
830                                         goto io_err;
831                         }
832                         brelse(bh);
833                 } while (++block < end_block);
834         } while ((++rl)->vcn < end_vcn);
835         up_write(&log_ni->runlist.lock);
836         /*
837          * Zap the pages again just in case any got instantiated whilst we were
838          * emptying the blocks by hand.  FIXME: We may not have completed
839          * writing to all the buffer heads yet so this may happen too early.
840          * We really should use a kernel thread to do the emptying
841          * asynchronously and then we can also set the volume dirty and output
842          * an error message if emptying should fail.
843          */
844         truncate_inode_pages(log_vi->i_mapping, 0);
845         /* Set the flag so we do not have to do it again on remount. */
846         NVolSetLogFileEmpty(vol);
847         ntfs_debug("Done.");
848         return true;
849 io_err:
850         ntfs_error(sb, "Failed to write buffer.  Unmount and run chkdsk.");
851         goto dirty_err;
852 rl_err:
853         ntfs_error(sb, "Runlist is corrupt.  Unmount and run chkdsk.");
854 dirty_err:
855         NVolSetErrors(vol);
856         err = -EIO;
857 err:
858         up_write(&log_ni->runlist.lock);
859         ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).",
860                         -err);
861         return false;
862 }
863 
864 #endif /* NTFS_RW */
865 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp