LCOV - code coverage report
Current view: top level - fsck.ubifs - handle_disconnected.c (source / functions) Hit Total Coverage
Test: a simple test Lines: 67 86 77.9 %
Date: 2024-06-05 20:10:43 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (C) 2024, Huawei Technologies Co, Ltd.
       4             :  *
       5             :  * Authors: Huang Xiaojia <huangxiaojia2@huawei.com>
       6             :  *          Zhihao Cheng <chengzhihao1@huawei.com>
       7             :  */
       8             : 
       9             : #include <stdio.h>
      10             : #include <stdlib.h>
      11             : #include <sys/stat.h>
      12             : 
      13             : #include "linux_err.h"
      14             : #include "kmem.h"
      15             : #include "ubifs.h"
      16             : #include "defs.h"
      17             : #include "debug.h"
      18             : #include "key.h"
      19             : #include "fsck.ubifs.h"
      20             : 
      21             : #define LOST_FOUND_DIR_NAME "lost+found"
      22             : #define MAX_REPEAT_NAME_RETRY_TIMES 10000000
      23             : 
      24             : /**
      25             :  * check_and_create_lost_found - Check and create the lost+found directory.
      26             :  * @c: UBIFS file-system description object
      27             :  *
      28             :  * This function checks whether the lost+found directory exists and creates a
      29             :  * new one if no valid lost+found existing. If there is a valid lost+found
      30             :  * directory, inode number is stored in @FSCK(c)->lost_and_found. Returns zero
      31             :  * in case of success, a negative error code in case of failure.
      32             :  */
      33          37 : int check_and_create_lost_found(struct ubifs_info *c)
      34             : {
      35             :         struct ubifs_inode *root_ui, *lost_found_ui;
      36             :         struct fscrypt_name nm;
      37          37 :         int err = 0;
      38             : 
      39          37 :         root_ui = ubifs_lookup_by_inum(c, UBIFS_ROOT_INO);
      40          37 :         if (IS_ERR(root_ui)) {
      41           0 :                 err = PTR_ERR(root_ui);
      42             :                 /* Previous step ensures that the root dir is valid. */
      43           0 :                 ubifs_assert(c, err != -ENOENT);
      44             :                 return err;
      45             :         }
      46             : 
      47          37 :         if (root_ui->flags & UBIFS_CRYPT_FL) {
      48           1 :                 ubifs_msg(c, "The root dir is encrypted, skip checking lost+found");
      49             :                 goto free_root;
      50             :         }
      51             : 
      52          36 :         fname_name(&nm) = LOST_FOUND_DIR_NAME;
      53          36 :         fname_len(&nm) = strlen(LOST_FOUND_DIR_NAME);
      54          36 :         lost_found_ui = ubifs_lookup(c, root_ui, &nm);
      55          36 :         if (IS_ERR(lost_found_ui)) {
      56          30 :                 err = PTR_ERR(lost_found_ui);
      57          30 :                 if (err != -ENOENT)
      58             :                         goto free_root;
      59             : 
      60             :                 /* Not found. Create a new lost+found. */
      61          30 :                 err = ubifs_mkdir(c, root_ui, &nm, S_IRUGO | S_IWUSR | S_IXUSR);
      62          30 :                 if (err < 0) {
      63           0 :                         if (err == -ENOSPC) {
      64           0 :                                 ubifs_msg(c, "No free space to create lost+found");
      65             :                                 err = 0;
      66             :                         }
      67             :                         goto free_root;
      68             :                 }
      69          30 :                 lost_found_ui = ubifs_lookup(c, root_ui, &nm);
      70          30 :                 if (IS_ERR(lost_found_ui)) {
      71           0 :                         err = PTR_ERR(lost_found_ui);
      72           0 :                         ubifs_assert(c, err != -ENOENT);
      73             :                         goto free_root;
      74             :                 }
      75          30 :                 FSCK(c)->lost_and_found = lost_found_ui->vfs_inode.inum;
      76          30 :                 ubifs_msg(c, "Create the lost+found");
      77          12 :         } else if (!(lost_found_ui->flags & UBIFS_CRYPT_FL) &&
      78           6 :                    S_ISDIR(lost_found_ui->vfs_inode.mode)) {
      79           3 :                 FSCK(c)->lost_and_found = lost_found_ui->vfs_inode.inum;
      80             :         } else {
      81           3 :                 ubifs_msg(c, "The type of lost+found is %s%s",
      82             :                           ubifs_get_type_name(ubifs_get_dent_type(lost_found_ui->vfs_inode.mode)),
      83             :                           lost_found_ui->flags & UBIFS_CRYPT_FL ? ", encrypted" : "");
      84             :         }
      85             : 
      86             :         kfree(lost_found_ui);
      87          37 : free_root:
      88          37 :         kfree(root_ui);
      89          37 :         return err;
      90             : }
      91             : 
      92         830 : static int handle_disonnected_file(struct ubifs_info *c,
      93             :                                    struct scanned_file *file)
      94             : {
      95         830 :         int err = 0;
      96             : 
      97         830 :         if (FSCK(c)->lost_and_found) {
      98         202 :                 unsigned int index = 0;
      99             :                 char file_name[UBIFS_MAX_NLEN + 1];
     100             :                 struct fscrypt_name nm;
     101         202 :                 struct ubifs_inode *ui = NULL, *lost_found_ui = NULL;
     102             : 
     103         202 :                 lost_found_ui = ubifs_lookup_by_inum(c, FSCK(c)->lost_and_found);
     104         202 :                 if (IS_ERR(lost_found_ui)) {
     105           0 :                         err = PTR_ERR(lost_found_ui);
     106           0 :                         ubifs_assert(c, err != -ENOENT);
     107         202 :                         return err;
     108             :                 }
     109         202 :                 ui = ubifs_lookup_by_inum(c, file->inum);
     110         202 :                 if (IS_ERR(ui)) {
     111           0 :                         err = PTR_ERR(ui);
     112           0 :                         ubifs_assert(c, err != -ENOENT);
     113             :                         goto free_lost_found_ui;
     114             :                 }
     115             : 
     116         205 :                 while (index < MAX_REPEAT_NAME_RETRY_TIMES) {
     117             :                         struct ubifs_inode *target_ui;
     118             : 
     119         205 :                         err = snprintf(file_name, sizeof(file_name),
     120             :                                        "INO_%lu_%u", file->inum, index);
     121         205 :                         if (err < 0)
     122             :                                 goto free_ui;
     123         205 :                         fname_name(&nm) = file_name;
     124         205 :                         fname_len(&nm) = strlen(file_name);
     125         205 :                         target_ui = ubifs_lookup(c, lost_found_ui, &nm);
     126         205 :                         if (IS_ERR(target_ui)) {
     127         202 :                                 err = PTR_ERR(target_ui);
     128         202 :                                 if (err == -ENOENT)
     129             :                                         break;
     130             :                                 goto free_ui;
     131             :                         }
     132           3 :                         kfree(target_ui);
     133           3 :                         index++;
     134             :                 }
     135             : 
     136         202 :                 if (err != -ENOENT) {
     137           0 :                         err = 0;
     138           0 :                         kfree(ui);
     139           0 :                         kfree(lost_found_ui);
     140           0 :                         log_out(c, "Too many duplicated names(%u) in lost+found for inum %lu",
     141             :                                 index, file->inum);
     142           0 :                         goto delete_file;
     143             :                 }
     144             : 
     145             :                 /* Try to recover disconnected file into lost+found. */
     146         202 :                 err = ubifs_link_recovery(c, lost_found_ui, ui, &nm);
     147         202 :                 if (err && err == -ENOSPC) {
     148           0 :                         err = 0;
     149           0 :                         log_out(c, "No free space to recover disconnected file");
     150           0 :                         goto delete_file;
     151             :                 }
     152         382 :                 dbg_fsck("recover disconnected file %lu, in %s",
     153             :                          file->inum, c->dev_name);
     154             : 
     155         224 : free_ui:
     156             :                 kfree(ui);
     157         202 : free_lost_found_ui:
     158         202 :                 kfree(lost_found_ui);
     159         202 :                 return err;
     160             :         } else
     161         628 :                 log_out(c, "No valid lost+found");
     162             : 
     163         628 : delete_file:
     164         628 :         if (fix_problem(c, DISCONNECTED_FILE_CANNOT_BE_RECOVERED, file))
     165         628 :                 err = delete_file(c, file);
     166             :         return err;
     167             : }
     168             : 
     169             : /**
     170             :  * handle_disonnected_files - Handle disconnected files.
     171             :  * @c: UBIFS file-system description object
     172             :  *
     173             :  * This function tries to recover disonnected files into lost+found directory.
     174             :  * If there is no free space left to recover the disconnected files, fsck may
     175             :  * delete the files to make filesystem be consistent. Returns zero in case of
     176             :  * success, a negative error code in case of failure.
     177             :  */
     178          37 : int handle_disonnected_files(struct ubifs_info *c)
     179             : {
     180          37 :         int err, ret = 0;
     181             :         struct scanned_file *file;
     182             : 
     183        1771 :         while (!list_empty(&FSCK(c)->disconnected_files)) {
     184         830 :                 file = list_entry(FSCK(c)->disconnected_files.next,
     185             :                                   struct scanned_file, list);
     186             : 
     187        1660 :                 list_del(&file->list);
     188         830 :                 err = handle_disonnected_file(c, file);
     189         830 :                 if (err)
     190           0 :                         ret = ret ? ret : err;
     191         830 :                 destroy_file_content(c, file);
     192             :                 kfree(file);
     193             :         }
     194             : 
     195          37 :         return ret;
     196             : }

Generated by: LCOV version 1.13