The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/ntfs/logfile.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 9f6184b599ec34b2f3df887e5368ae6f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.