18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * super.c - NILFS module and super block management. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Written by Ryusuke Konishi. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * linux/fs/ext2/super.c 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 138c2ecf20Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 148c2ecf20Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal 158c2ecf20Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI) 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * from 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * linux/fs/minix/inode.c 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Big-endian to little-endian byte-swapping/bitmaps by 248c2ecf20Sopenharmony_ci * David S. Miller (davem@caip.rutgers.edu), 1995 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/module.h> 288c2ecf20Sopenharmony_ci#include <linux/string.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/init.h> 318c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 328c2ecf20Sopenharmony_ci#include <linux/parser.h> 338c2ecf20Sopenharmony_ci#include <linux/crc32.h> 348c2ecf20Sopenharmony_ci#include <linux/vfs.h> 358c2ecf20Sopenharmony_ci#include <linux/writeback.h> 368c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 378c2ecf20Sopenharmony_ci#include <linux/mount.h> 388c2ecf20Sopenharmony_ci#include "nilfs.h" 398c2ecf20Sopenharmony_ci#include "export.h" 408c2ecf20Sopenharmony_ci#include "mdt.h" 418c2ecf20Sopenharmony_ci#include "alloc.h" 428c2ecf20Sopenharmony_ci#include "btree.h" 438c2ecf20Sopenharmony_ci#include "btnode.h" 448c2ecf20Sopenharmony_ci#include "page.h" 458c2ecf20Sopenharmony_ci#include "cpfile.h" 468c2ecf20Sopenharmony_ci#include "sufile.h" /* nilfs_sufile_resize(), nilfs_sufile_set_alloc_range() */ 478c2ecf20Sopenharmony_ci#include "ifile.h" 488c2ecf20Sopenharmony_ci#include "dat.h" 498c2ecf20Sopenharmony_ci#include "segment.h" 508c2ecf20Sopenharmony_ci#include "segbuf.h" 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciMODULE_AUTHOR("NTT Corp."); 538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem " 548c2ecf20Sopenharmony_ci "(NILFS)"); 558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic struct kmem_cache *nilfs_inode_cachep; 588c2ecf20Sopenharmony_cistruct kmem_cache *nilfs_transaction_cachep; 598c2ecf20Sopenharmony_cistruct kmem_cache *nilfs_segbuf_cachep; 608c2ecf20Sopenharmony_cistruct kmem_cache *nilfs_btree_path_cache; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int nilfs_setup_super(struct super_block *sb, int is_mount); 638c2ecf20Sopenharmony_cistatic int nilfs_remount(struct super_block *sb, int *flags, char *data); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_civoid __nilfs_msg(struct super_block *sb, const char *fmt, ...) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct va_format vaf; 688c2ecf20Sopenharmony_ci va_list args; 698c2ecf20Sopenharmony_ci int level; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci va_start(args, fmt); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci level = printk_get_level(fmt); 748c2ecf20Sopenharmony_ci vaf.fmt = printk_skip_level(fmt); 758c2ecf20Sopenharmony_ci vaf.va = &args; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (sb) 788c2ecf20Sopenharmony_ci printk("%c%cNILFS (%s): %pV\n", 798c2ecf20Sopenharmony_ci KERN_SOH_ASCII, level, sb->s_id, &vaf); 808c2ecf20Sopenharmony_ci else 818c2ecf20Sopenharmony_ci printk("%c%cNILFS: %pV\n", 828c2ecf20Sopenharmony_ci KERN_SOH_ASCII, level, &vaf); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci va_end(args); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void nilfs_set_error(struct super_block *sb) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 908c2ecf20Sopenharmony_ci struct nilfs_super_block **sbp; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci down_write(&nilfs->ns_sem); 938c2ecf20Sopenharmony_ci if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) { 948c2ecf20Sopenharmony_ci nilfs->ns_mount_state |= NILFS_ERROR_FS; 958c2ecf20Sopenharmony_ci sbp = nilfs_prepare_super(sb, 0); 968c2ecf20Sopenharmony_ci if (likely(sbp)) { 978c2ecf20Sopenharmony_ci sbp[0]->s_state |= cpu_to_le16(NILFS_ERROR_FS); 988c2ecf20Sopenharmony_ci if (sbp[1]) 998c2ecf20Sopenharmony_ci sbp[1]->s_state |= cpu_to_le16(NILFS_ERROR_FS); 1008c2ecf20Sopenharmony_ci nilfs_commit_super(sb, NILFS_SB_COMMIT_ALL); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci up_write(&nilfs->ns_sem); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/** 1078c2ecf20Sopenharmony_ci * __nilfs_error() - report failure condition on a filesystem 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * __nilfs_error() sets an ERROR_FS flag on the superblock as well as 1108c2ecf20Sopenharmony_ci * reporting an error message. This function should be called when 1118c2ecf20Sopenharmony_ci * NILFS detects incoherences or defects of meta data on disk. 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * This implements the body of nilfs_error() macro. Normally, 1148c2ecf20Sopenharmony_ci * nilfs_error() should be used. As for sustainable errors such as a 1158c2ecf20Sopenharmony_ci * single-shot I/O error, nilfs_err() should be used instead. 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * Callers should not add a trailing newline since this will do it. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_civoid __nilfs_error(struct super_block *sb, const char *function, 1208c2ecf20Sopenharmony_ci const char *fmt, ...) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 1238c2ecf20Sopenharmony_ci struct va_format vaf; 1248c2ecf20Sopenharmony_ci va_list args; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci va_start(args, fmt); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci vaf.fmt = fmt; 1298c2ecf20Sopenharmony_ci vaf.va = &args; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci printk(KERN_CRIT "NILFS error (device %s): %s: %pV\n", 1328c2ecf20Sopenharmony_ci sb->s_id, function, &vaf); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci va_end(args); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 1378c2ecf20Sopenharmony_ci nilfs_set_error(sb); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (nilfs_test_opt(nilfs, ERRORS_RO)) { 1408c2ecf20Sopenharmony_ci printk(KERN_CRIT "Remounting filesystem read-only\n"); 1418c2ecf20Sopenharmony_ci sb->s_flags |= SB_RDONLY; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (nilfs_test_opt(nilfs, ERRORS_PANIC)) 1468c2ecf20Sopenharmony_ci panic("NILFS (device %s): panic forced after error\n", 1478c2ecf20Sopenharmony_ci sb->s_id); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistruct inode *nilfs_alloc_inode(struct super_block *sb) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct nilfs_inode_info *ii; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ii = kmem_cache_alloc(nilfs_inode_cachep, GFP_NOFS); 1558c2ecf20Sopenharmony_ci if (!ii) 1568c2ecf20Sopenharmony_ci return NULL; 1578c2ecf20Sopenharmony_ci ii->i_bh = NULL; 1588c2ecf20Sopenharmony_ci ii->i_state = 0; 1598c2ecf20Sopenharmony_ci ii->i_cno = 0; 1608c2ecf20Sopenharmony_ci ii->i_assoc_inode = NULL; 1618c2ecf20Sopenharmony_ci ii->i_bmap = &ii->i_bmap_data; 1628c2ecf20Sopenharmony_ci return &ii->vfs_inode; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void nilfs_free_inode(struct inode *inode) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci if (nilfs_is_metadata_file_inode(inode)) 1688c2ecf20Sopenharmony_ci nilfs_mdt_destroy(inode); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int nilfs_sync_super(struct super_block *sb, int flag) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 1768c2ecf20Sopenharmony_ci int err; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci retry: 1798c2ecf20Sopenharmony_ci set_buffer_dirty(nilfs->ns_sbh[0]); 1808c2ecf20Sopenharmony_ci if (nilfs_test_opt(nilfs, BARRIER)) { 1818c2ecf20Sopenharmony_ci err = __sync_dirty_buffer(nilfs->ns_sbh[0], 1828c2ecf20Sopenharmony_ci REQ_SYNC | REQ_PREFLUSH | REQ_FUA); 1838c2ecf20Sopenharmony_ci } else { 1848c2ecf20Sopenharmony_ci err = sync_dirty_buffer(nilfs->ns_sbh[0]); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (unlikely(err)) { 1888c2ecf20Sopenharmony_ci nilfs_err(sb, "unable to write superblock: err=%d", err); 1898c2ecf20Sopenharmony_ci if (err == -EIO && nilfs->ns_sbh[1]) { 1908c2ecf20Sopenharmony_ci /* 1918c2ecf20Sopenharmony_ci * sbp[0] points to newer log than sbp[1], 1928c2ecf20Sopenharmony_ci * so copy sbp[0] to sbp[1] to take over sbp[0]. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ci memcpy(nilfs->ns_sbp[1], nilfs->ns_sbp[0], 1958c2ecf20Sopenharmony_ci nilfs->ns_sbsize); 1968c2ecf20Sopenharmony_ci nilfs_fall_back_super_block(nilfs); 1978c2ecf20Sopenharmony_ci goto retry; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci } else { 2008c2ecf20Sopenharmony_ci struct nilfs_super_block *sbp = nilfs->ns_sbp[0]; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci nilfs->ns_sbwcount++; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * The latest segment becomes trailable from the position 2068c2ecf20Sopenharmony_ci * written in superblock. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci clear_nilfs_discontinued(nilfs); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* update GC protection for recent segments */ 2118c2ecf20Sopenharmony_ci if (nilfs->ns_sbh[1]) { 2128c2ecf20Sopenharmony_ci if (flag == NILFS_SB_COMMIT_ALL) { 2138c2ecf20Sopenharmony_ci set_buffer_dirty(nilfs->ns_sbh[1]); 2148c2ecf20Sopenharmony_ci if (sync_dirty_buffer(nilfs->ns_sbh[1]) < 0) 2158c2ecf20Sopenharmony_ci goto out; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci if (le64_to_cpu(nilfs->ns_sbp[1]->s_last_cno) < 2188c2ecf20Sopenharmony_ci le64_to_cpu(nilfs->ns_sbp[0]->s_last_cno)) 2198c2ecf20Sopenharmony_ci sbp = nilfs->ns_sbp[1]; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci spin_lock(&nilfs->ns_last_segment_lock); 2238c2ecf20Sopenharmony_ci nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq); 2248c2ecf20Sopenharmony_ci spin_unlock(&nilfs->ns_last_segment_lock); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci out: 2278c2ecf20Sopenharmony_ci return err; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_civoid nilfs_set_log_cursor(struct nilfs_super_block *sbp, 2318c2ecf20Sopenharmony_ci struct the_nilfs *nilfs) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci sector_t nfreeblocks; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* nilfs->ns_sem must be locked by the caller. */ 2368c2ecf20Sopenharmony_ci nilfs_count_free_blocks(nilfs, &nfreeblocks); 2378c2ecf20Sopenharmony_ci sbp->s_free_blocks_count = cpu_to_le64(nfreeblocks); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci spin_lock(&nilfs->ns_last_segment_lock); 2408c2ecf20Sopenharmony_ci sbp->s_last_seq = cpu_to_le64(nilfs->ns_last_seq); 2418c2ecf20Sopenharmony_ci sbp->s_last_pseg = cpu_to_le64(nilfs->ns_last_pseg); 2428c2ecf20Sopenharmony_ci sbp->s_last_cno = cpu_to_le64(nilfs->ns_last_cno); 2438c2ecf20Sopenharmony_ci spin_unlock(&nilfs->ns_last_segment_lock); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistruct nilfs_super_block **nilfs_prepare_super(struct super_block *sb, 2478c2ecf20Sopenharmony_ci int flip) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 2508c2ecf20Sopenharmony_ci struct nilfs_super_block **sbp = nilfs->ns_sbp; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* nilfs->ns_sem must be locked by the caller. */ 2538c2ecf20Sopenharmony_ci if (sbp[0]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) { 2548c2ecf20Sopenharmony_ci if (sbp[1] && 2558c2ecf20Sopenharmony_ci sbp[1]->s_magic == cpu_to_le16(NILFS_SUPER_MAGIC)) { 2568c2ecf20Sopenharmony_ci memcpy(sbp[0], sbp[1], nilfs->ns_sbsize); 2578c2ecf20Sopenharmony_ci } else { 2588c2ecf20Sopenharmony_ci nilfs_crit(sb, "superblock broke"); 2598c2ecf20Sopenharmony_ci return NULL; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } else if (sbp[1] && 2628c2ecf20Sopenharmony_ci sbp[1]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) { 2638c2ecf20Sopenharmony_ci memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (flip && sbp[1]) 2678c2ecf20Sopenharmony_ci nilfs_swap_super_block(nilfs); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return sbp; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ciint nilfs_commit_super(struct super_block *sb, int flag) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 2758c2ecf20Sopenharmony_ci struct nilfs_super_block **sbp = nilfs->ns_sbp; 2768c2ecf20Sopenharmony_ci time64_t t; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* nilfs->ns_sem must be locked by the caller. */ 2798c2ecf20Sopenharmony_ci t = ktime_get_real_seconds(); 2808c2ecf20Sopenharmony_ci nilfs->ns_sbwtime = t; 2818c2ecf20Sopenharmony_ci sbp[0]->s_wtime = cpu_to_le64(t); 2828c2ecf20Sopenharmony_ci sbp[0]->s_sum = 0; 2838c2ecf20Sopenharmony_ci sbp[0]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed, 2848c2ecf20Sopenharmony_ci (unsigned char *)sbp[0], 2858c2ecf20Sopenharmony_ci nilfs->ns_sbsize)); 2868c2ecf20Sopenharmony_ci if (flag == NILFS_SB_COMMIT_ALL && sbp[1]) { 2878c2ecf20Sopenharmony_ci sbp[1]->s_wtime = sbp[0]->s_wtime; 2888c2ecf20Sopenharmony_ci sbp[1]->s_sum = 0; 2898c2ecf20Sopenharmony_ci sbp[1]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed, 2908c2ecf20Sopenharmony_ci (unsigned char *)sbp[1], 2918c2ecf20Sopenharmony_ci nilfs->ns_sbsize)); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci clear_nilfs_sb_dirty(nilfs); 2948c2ecf20Sopenharmony_ci nilfs->ns_flushed_device = 1; 2958c2ecf20Sopenharmony_ci /* make sure store to ns_flushed_device cannot be reordered */ 2968c2ecf20Sopenharmony_ci smp_wmb(); 2978c2ecf20Sopenharmony_ci return nilfs_sync_super(sb, flag); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/** 3018c2ecf20Sopenharmony_ci * nilfs_cleanup_super() - write filesystem state for cleanup 3028c2ecf20Sopenharmony_ci * @sb: super block instance to be unmounted or degraded to read-only 3038c2ecf20Sopenharmony_ci * 3048c2ecf20Sopenharmony_ci * This function restores state flags in the on-disk super block. 3058c2ecf20Sopenharmony_ci * This will set "clean" flag (i.e. NILFS_VALID_FS) unless the 3068c2ecf20Sopenharmony_ci * filesystem was not clean previously. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ciint nilfs_cleanup_super(struct super_block *sb) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 3118c2ecf20Sopenharmony_ci struct nilfs_super_block **sbp; 3128c2ecf20Sopenharmony_ci int flag = NILFS_SB_COMMIT; 3138c2ecf20Sopenharmony_ci int ret = -EIO; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci sbp = nilfs_prepare_super(sb, 0); 3168c2ecf20Sopenharmony_ci if (sbp) { 3178c2ecf20Sopenharmony_ci sbp[0]->s_state = cpu_to_le16(nilfs->ns_mount_state); 3188c2ecf20Sopenharmony_ci nilfs_set_log_cursor(sbp[0], nilfs); 3198c2ecf20Sopenharmony_ci if (sbp[1] && sbp[0]->s_last_cno == sbp[1]->s_last_cno) { 3208c2ecf20Sopenharmony_ci /* 3218c2ecf20Sopenharmony_ci * make the "clean" flag also to the opposite 3228c2ecf20Sopenharmony_ci * super block if both super blocks point to 3238c2ecf20Sopenharmony_ci * the same checkpoint. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci sbp[1]->s_state = sbp[0]->s_state; 3268c2ecf20Sopenharmony_ci flag = NILFS_SB_COMMIT_ALL; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci ret = nilfs_commit_super(sb, flag); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/** 3348c2ecf20Sopenharmony_ci * nilfs_move_2nd_super - relocate secondary super block 3358c2ecf20Sopenharmony_ci * @sb: super block instance 3368c2ecf20Sopenharmony_ci * @sb2off: new offset of the secondary super block (in bytes) 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_cistatic int nilfs_move_2nd_super(struct super_block *sb, loff_t sb2off) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 3418c2ecf20Sopenharmony_ci struct buffer_head *nsbh; 3428c2ecf20Sopenharmony_ci struct nilfs_super_block *nsbp; 3438c2ecf20Sopenharmony_ci sector_t blocknr, newblocknr; 3448c2ecf20Sopenharmony_ci unsigned long offset; 3458c2ecf20Sopenharmony_ci int sb2i; /* array index of the secondary superblock */ 3468c2ecf20Sopenharmony_ci int ret = 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* nilfs->ns_sem must be locked by the caller. */ 3498c2ecf20Sopenharmony_ci if (nilfs->ns_sbh[1] && 3508c2ecf20Sopenharmony_ci nilfs->ns_sbh[1]->b_blocknr > nilfs->ns_first_data_block) { 3518c2ecf20Sopenharmony_ci sb2i = 1; 3528c2ecf20Sopenharmony_ci blocknr = nilfs->ns_sbh[1]->b_blocknr; 3538c2ecf20Sopenharmony_ci } else if (nilfs->ns_sbh[0]->b_blocknr > nilfs->ns_first_data_block) { 3548c2ecf20Sopenharmony_ci sb2i = 0; 3558c2ecf20Sopenharmony_ci blocknr = nilfs->ns_sbh[0]->b_blocknr; 3568c2ecf20Sopenharmony_ci } else { 3578c2ecf20Sopenharmony_ci sb2i = -1; 3588c2ecf20Sopenharmony_ci blocknr = 0; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci if (sb2i >= 0 && (u64)blocknr << nilfs->ns_blocksize_bits == sb2off) 3618c2ecf20Sopenharmony_ci goto out; /* super block location is unchanged */ 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Get new super block buffer */ 3648c2ecf20Sopenharmony_ci newblocknr = sb2off >> nilfs->ns_blocksize_bits; 3658c2ecf20Sopenharmony_ci offset = sb2off & (nilfs->ns_blocksize - 1); 3668c2ecf20Sopenharmony_ci nsbh = sb_getblk(sb, newblocknr); 3678c2ecf20Sopenharmony_ci if (!nsbh) { 3688c2ecf20Sopenharmony_ci nilfs_warn(sb, 3698c2ecf20Sopenharmony_ci "unable to move secondary superblock to block %llu", 3708c2ecf20Sopenharmony_ci (unsigned long long)newblocknr); 3718c2ecf20Sopenharmony_ci ret = -EIO; 3728c2ecf20Sopenharmony_ci goto out; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci nsbp = (void *)nsbh->b_data + offset; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci lock_buffer(nsbh); 3778c2ecf20Sopenharmony_ci if (sb2i >= 0) { 3788c2ecf20Sopenharmony_ci /* 3798c2ecf20Sopenharmony_ci * The position of the second superblock only changes by 4KiB, 3808c2ecf20Sopenharmony_ci * which is larger than the maximum superblock data size 3818c2ecf20Sopenharmony_ci * (= 1KiB), so there is no need to use memmove() to allow 3828c2ecf20Sopenharmony_ci * overlap between source and destination. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci memcpy(nsbp, nilfs->ns_sbp[sb2i], nilfs->ns_sbsize); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci * Zero fill after copy to avoid overwriting in case of move 3888c2ecf20Sopenharmony_ci * within the same block. 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_ci memset(nsbh->b_data, 0, offset); 3918c2ecf20Sopenharmony_ci memset((void *)nsbp + nilfs->ns_sbsize, 0, 3928c2ecf20Sopenharmony_ci nsbh->b_size - offset - nilfs->ns_sbsize); 3938c2ecf20Sopenharmony_ci } else { 3948c2ecf20Sopenharmony_ci memset(nsbh->b_data, 0, nsbh->b_size); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci set_buffer_uptodate(nsbh); 3978c2ecf20Sopenharmony_ci unlock_buffer(nsbh); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (sb2i >= 0) { 4008c2ecf20Sopenharmony_ci brelse(nilfs->ns_sbh[sb2i]); 4018c2ecf20Sopenharmony_ci nilfs->ns_sbh[sb2i] = nsbh; 4028c2ecf20Sopenharmony_ci nilfs->ns_sbp[sb2i] = nsbp; 4038c2ecf20Sopenharmony_ci } else if (nilfs->ns_sbh[0]->b_blocknr < nilfs->ns_first_data_block) { 4048c2ecf20Sopenharmony_ci /* secondary super block will be restored to index 1 */ 4058c2ecf20Sopenharmony_ci nilfs->ns_sbh[1] = nsbh; 4068c2ecf20Sopenharmony_ci nilfs->ns_sbp[1] = nsbp; 4078c2ecf20Sopenharmony_ci } else { 4088c2ecf20Sopenharmony_ci brelse(nsbh); 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ciout: 4118c2ecf20Sopenharmony_ci return ret; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/** 4158c2ecf20Sopenharmony_ci * nilfs_resize_fs - resize the filesystem 4168c2ecf20Sopenharmony_ci * @sb: super block instance 4178c2ecf20Sopenharmony_ci * @newsize: new size of the filesystem (in bytes) 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ciint nilfs_resize_fs(struct super_block *sb, __u64 newsize) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 4228c2ecf20Sopenharmony_ci struct nilfs_super_block **sbp; 4238c2ecf20Sopenharmony_ci __u64 devsize, newnsegs; 4248c2ecf20Sopenharmony_ci loff_t sb2off; 4258c2ecf20Sopenharmony_ci int ret; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ret = -ERANGE; 4288c2ecf20Sopenharmony_ci devsize = i_size_read(sb->s_bdev->bd_inode); 4298c2ecf20Sopenharmony_ci if (newsize > devsize) 4308c2ecf20Sopenharmony_ci goto out; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* 4338c2ecf20Sopenharmony_ci * Prevent underflow in second superblock position calculation. 4348c2ecf20Sopenharmony_ci * The exact minimum size check is done in nilfs_sufile_resize(). 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_ci if (newsize < 4096) { 4378c2ecf20Sopenharmony_ci ret = -ENOSPC; 4388c2ecf20Sopenharmony_ci goto out; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* 4428c2ecf20Sopenharmony_ci * Write lock is required to protect some functions depending 4438c2ecf20Sopenharmony_ci * on the number of segments, the number of reserved segments, 4448c2ecf20Sopenharmony_ci * and so forth. 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_ci down_write(&nilfs->ns_segctor_sem); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci sb2off = NILFS_SB2_OFFSET_BYTES(newsize); 4498c2ecf20Sopenharmony_ci newnsegs = sb2off >> nilfs->ns_blocksize_bits; 4508c2ecf20Sopenharmony_ci do_div(newnsegs, nilfs->ns_blocks_per_segment); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci ret = nilfs_sufile_resize(nilfs->ns_sufile, newnsegs); 4538c2ecf20Sopenharmony_ci up_write(&nilfs->ns_segctor_sem); 4548c2ecf20Sopenharmony_ci if (ret < 0) 4558c2ecf20Sopenharmony_ci goto out; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci ret = nilfs_construct_segment(sb); 4588c2ecf20Sopenharmony_ci if (ret < 0) 4598c2ecf20Sopenharmony_ci goto out; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci down_write(&nilfs->ns_sem); 4628c2ecf20Sopenharmony_ci nilfs_move_2nd_super(sb, sb2off); 4638c2ecf20Sopenharmony_ci ret = -EIO; 4648c2ecf20Sopenharmony_ci sbp = nilfs_prepare_super(sb, 0); 4658c2ecf20Sopenharmony_ci if (likely(sbp)) { 4668c2ecf20Sopenharmony_ci nilfs_set_log_cursor(sbp[0], nilfs); 4678c2ecf20Sopenharmony_ci /* 4688c2ecf20Sopenharmony_ci * Drop NILFS_RESIZE_FS flag for compatibility with 4698c2ecf20Sopenharmony_ci * mount-time resize which may be implemented in a 4708c2ecf20Sopenharmony_ci * future release. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_ci sbp[0]->s_state = cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & 4738c2ecf20Sopenharmony_ci ~NILFS_RESIZE_FS); 4748c2ecf20Sopenharmony_ci sbp[0]->s_dev_size = cpu_to_le64(newsize); 4758c2ecf20Sopenharmony_ci sbp[0]->s_nsegments = cpu_to_le64(nilfs->ns_nsegments); 4768c2ecf20Sopenharmony_ci if (sbp[1]) 4778c2ecf20Sopenharmony_ci memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); 4788c2ecf20Sopenharmony_ci ret = nilfs_commit_super(sb, NILFS_SB_COMMIT_ALL); 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci up_write(&nilfs->ns_sem); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* 4838c2ecf20Sopenharmony_ci * Reset the range of allocatable segments last. This order 4848c2ecf20Sopenharmony_ci * is important in the case of expansion because the secondary 4858c2ecf20Sopenharmony_ci * superblock must be protected from log write until migration 4868c2ecf20Sopenharmony_ci * completes. 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_ci if (!ret) 4898c2ecf20Sopenharmony_ci nilfs_sufile_set_alloc_range(nilfs->ns_sufile, 0, newnsegs - 1); 4908c2ecf20Sopenharmony_ciout: 4918c2ecf20Sopenharmony_ci return ret; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic void nilfs_put_super(struct super_block *sb) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci nilfs_detach_log_writer(sb); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 5018c2ecf20Sopenharmony_ci down_write(&nilfs->ns_sem); 5028c2ecf20Sopenharmony_ci nilfs_cleanup_super(sb); 5038c2ecf20Sopenharmony_ci up_write(&nilfs->ns_sem); 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci nilfs_sysfs_delete_device_group(nilfs); 5078c2ecf20Sopenharmony_ci iput(nilfs->ns_sufile); 5088c2ecf20Sopenharmony_ci iput(nilfs->ns_cpfile); 5098c2ecf20Sopenharmony_ci iput(nilfs->ns_dat); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci destroy_nilfs(nilfs); 5128c2ecf20Sopenharmony_ci sb->s_fs_info = NULL; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int nilfs_sync_fs(struct super_block *sb, int wait) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 5188c2ecf20Sopenharmony_ci struct nilfs_super_block **sbp; 5198c2ecf20Sopenharmony_ci int err = 0; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* This function is called when super block should be written back */ 5228c2ecf20Sopenharmony_ci if (wait) 5238c2ecf20Sopenharmony_ci err = nilfs_construct_segment(sb); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci down_write(&nilfs->ns_sem); 5268c2ecf20Sopenharmony_ci if (nilfs_sb_dirty(nilfs)) { 5278c2ecf20Sopenharmony_ci sbp = nilfs_prepare_super(sb, nilfs_sb_will_flip(nilfs)); 5288c2ecf20Sopenharmony_ci if (likely(sbp)) { 5298c2ecf20Sopenharmony_ci nilfs_set_log_cursor(sbp[0], nilfs); 5308c2ecf20Sopenharmony_ci nilfs_commit_super(sb, NILFS_SB_COMMIT); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci up_write(&nilfs->ns_sem); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (!err) 5368c2ecf20Sopenharmony_ci err = nilfs_flush_device(nilfs); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return err; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ciint nilfs_attach_checkpoint(struct super_block *sb, __u64 cno, int curr_mnt, 5428c2ecf20Sopenharmony_ci struct nilfs_root **rootp) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 5458c2ecf20Sopenharmony_ci struct nilfs_root *root; 5468c2ecf20Sopenharmony_ci struct nilfs_checkpoint *raw_cp; 5478c2ecf20Sopenharmony_ci struct buffer_head *bh_cp; 5488c2ecf20Sopenharmony_ci int err = -ENOMEM; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci root = nilfs_find_or_create_root( 5518c2ecf20Sopenharmony_ci nilfs, curr_mnt ? NILFS_CPTREE_CURRENT_CNO : cno); 5528c2ecf20Sopenharmony_ci if (!root) 5538c2ecf20Sopenharmony_ci return err; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (root->ifile) 5568c2ecf20Sopenharmony_ci goto reuse; /* already attached checkpoint */ 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 5598c2ecf20Sopenharmony_ci err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp, 5608c2ecf20Sopenharmony_ci &bh_cp); 5618c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 5628c2ecf20Sopenharmony_ci if (unlikely(err)) { 5638c2ecf20Sopenharmony_ci if (err == -ENOENT || err == -EINVAL) { 5648c2ecf20Sopenharmony_ci nilfs_err(sb, 5658c2ecf20Sopenharmony_ci "Invalid checkpoint (checkpoint number=%llu)", 5668c2ecf20Sopenharmony_ci (unsigned long long)cno); 5678c2ecf20Sopenharmony_ci err = -EINVAL; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci goto failed; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci err = nilfs_ifile_read(sb, root, nilfs->ns_inode_size, 5738c2ecf20Sopenharmony_ci &raw_cp->cp_ifile_inode, &root->ifile); 5748c2ecf20Sopenharmony_ci if (err) 5758c2ecf20Sopenharmony_ci goto failed_bh; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci atomic64_set(&root->inodes_count, 5788c2ecf20Sopenharmony_ci le64_to_cpu(raw_cp->cp_inodes_count)); 5798c2ecf20Sopenharmony_ci atomic64_set(&root->blocks_count, 5808c2ecf20Sopenharmony_ci le64_to_cpu(raw_cp->cp_blocks_count)); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci reuse: 5858c2ecf20Sopenharmony_ci *rootp = root; 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci failed_bh: 5898c2ecf20Sopenharmony_ci nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); 5908c2ecf20Sopenharmony_ci failed: 5918c2ecf20Sopenharmony_ci nilfs_put_root(root); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci return err; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic int nilfs_freeze(struct super_block *sb) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 5998c2ecf20Sopenharmony_ci int err; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* Mark super block clean */ 6058c2ecf20Sopenharmony_ci down_write(&nilfs->ns_sem); 6068c2ecf20Sopenharmony_ci err = nilfs_cleanup_super(sb); 6078c2ecf20Sopenharmony_ci up_write(&nilfs->ns_sem); 6088c2ecf20Sopenharmony_ci return err; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int nilfs_unfreeze(struct super_block *sb) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci down_write(&nilfs->ns_sem); 6198c2ecf20Sopenharmony_ci nilfs_setup_super(sb, false); 6208c2ecf20Sopenharmony_ci up_write(&nilfs->ns_sem); 6218c2ecf20Sopenharmony_ci return 0; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct super_block *sb = dentry->d_sb; 6278c2ecf20Sopenharmony_ci struct nilfs_root *root = NILFS_I(d_inode(dentry))->i_root; 6288c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = root->nilfs; 6298c2ecf20Sopenharmony_ci u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 6308c2ecf20Sopenharmony_ci unsigned long long blocks; 6318c2ecf20Sopenharmony_ci unsigned long overhead; 6328c2ecf20Sopenharmony_ci unsigned long nrsvblocks; 6338c2ecf20Sopenharmony_ci sector_t nfreeblocks; 6348c2ecf20Sopenharmony_ci u64 nmaxinodes, nfreeinodes; 6358c2ecf20Sopenharmony_ci int err; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* 6388c2ecf20Sopenharmony_ci * Compute all of the segment blocks 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci * The blocks before first segment and after last segment 6418c2ecf20Sopenharmony_ci * are excluded. 6428c2ecf20Sopenharmony_ci */ 6438c2ecf20Sopenharmony_ci blocks = nilfs->ns_blocks_per_segment * nilfs->ns_nsegments 6448c2ecf20Sopenharmony_ci - nilfs->ns_first_data_block; 6458c2ecf20Sopenharmony_ci nrsvblocks = nilfs->ns_nrsvsegs * nilfs->ns_blocks_per_segment; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Compute the overhead 6498c2ecf20Sopenharmony_ci * 6508c2ecf20Sopenharmony_ci * When distributing meta data blocks outside segment structure, 6518c2ecf20Sopenharmony_ci * We must count them as the overhead. 6528c2ecf20Sopenharmony_ci */ 6538c2ecf20Sopenharmony_ci overhead = 0; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci err = nilfs_count_free_blocks(nilfs, &nfreeblocks); 6568c2ecf20Sopenharmony_ci if (unlikely(err)) 6578c2ecf20Sopenharmony_ci return err; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci err = nilfs_ifile_count_free_inodes(root->ifile, 6608c2ecf20Sopenharmony_ci &nmaxinodes, &nfreeinodes); 6618c2ecf20Sopenharmony_ci if (unlikely(err)) { 6628c2ecf20Sopenharmony_ci nilfs_warn(sb, "failed to count free inodes: err=%d", err); 6638c2ecf20Sopenharmony_ci if (err == -ERANGE) { 6648c2ecf20Sopenharmony_ci /* 6658c2ecf20Sopenharmony_ci * If nilfs_palloc_count_max_entries() returns 6668c2ecf20Sopenharmony_ci * -ERANGE error code then we simply treat 6678c2ecf20Sopenharmony_ci * curent inodes count as maximum possible and 6688c2ecf20Sopenharmony_ci * zero as free inodes value. 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci nmaxinodes = atomic64_read(&root->inodes_count); 6718c2ecf20Sopenharmony_ci nfreeinodes = 0; 6728c2ecf20Sopenharmony_ci err = 0; 6738c2ecf20Sopenharmony_ci } else 6748c2ecf20Sopenharmony_ci return err; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci buf->f_type = NILFS_SUPER_MAGIC; 6788c2ecf20Sopenharmony_ci buf->f_bsize = sb->s_blocksize; 6798c2ecf20Sopenharmony_ci buf->f_blocks = blocks - overhead; 6808c2ecf20Sopenharmony_ci buf->f_bfree = nfreeblocks; 6818c2ecf20Sopenharmony_ci buf->f_bavail = (buf->f_bfree >= nrsvblocks) ? 6828c2ecf20Sopenharmony_ci (buf->f_bfree - nrsvblocks) : 0; 6838c2ecf20Sopenharmony_ci buf->f_files = nmaxinodes; 6848c2ecf20Sopenharmony_ci buf->f_ffree = nfreeinodes; 6858c2ecf20Sopenharmony_ci buf->f_namelen = NILFS_NAME_LEN; 6868c2ecf20Sopenharmony_ci buf->f_fsid = u64_to_fsid(id); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return 0; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int nilfs_show_options(struct seq_file *seq, struct dentry *dentry) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct super_block *sb = dentry->d_sb; 6948c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 6958c2ecf20Sopenharmony_ci struct nilfs_root *root = NILFS_I(d_inode(dentry))->i_root; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (!nilfs_test_opt(nilfs, BARRIER)) 6988c2ecf20Sopenharmony_ci seq_puts(seq, ",nobarrier"); 6998c2ecf20Sopenharmony_ci if (root->cno != NILFS_CPTREE_CURRENT_CNO) 7008c2ecf20Sopenharmony_ci seq_printf(seq, ",cp=%llu", (unsigned long long)root->cno); 7018c2ecf20Sopenharmony_ci if (nilfs_test_opt(nilfs, ERRORS_PANIC)) 7028c2ecf20Sopenharmony_ci seq_puts(seq, ",errors=panic"); 7038c2ecf20Sopenharmony_ci if (nilfs_test_opt(nilfs, ERRORS_CONT)) 7048c2ecf20Sopenharmony_ci seq_puts(seq, ",errors=continue"); 7058c2ecf20Sopenharmony_ci if (nilfs_test_opt(nilfs, STRICT_ORDER)) 7068c2ecf20Sopenharmony_ci seq_puts(seq, ",order=strict"); 7078c2ecf20Sopenharmony_ci if (nilfs_test_opt(nilfs, NORECOVERY)) 7088c2ecf20Sopenharmony_ci seq_puts(seq, ",norecovery"); 7098c2ecf20Sopenharmony_ci if (nilfs_test_opt(nilfs, DISCARD)) 7108c2ecf20Sopenharmony_ci seq_puts(seq, ",discard"); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci return 0; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic const struct super_operations nilfs_sops = { 7168c2ecf20Sopenharmony_ci .alloc_inode = nilfs_alloc_inode, 7178c2ecf20Sopenharmony_ci .free_inode = nilfs_free_inode, 7188c2ecf20Sopenharmony_ci .dirty_inode = nilfs_dirty_inode, 7198c2ecf20Sopenharmony_ci .evict_inode = nilfs_evict_inode, 7208c2ecf20Sopenharmony_ci .put_super = nilfs_put_super, 7218c2ecf20Sopenharmony_ci .sync_fs = nilfs_sync_fs, 7228c2ecf20Sopenharmony_ci .freeze_fs = nilfs_freeze, 7238c2ecf20Sopenharmony_ci .unfreeze_fs = nilfs_unfreeze, 7248c2ecf20Sopenharmony_ci .statfs = nilfs_statfs, 7258c2ecf20Sopenharmony_ci .remount_fs = nilfs_remount, 7268c2ecf20Sopenharmony_ci .show_options = nilfs_show_options 7278c2ecf20Sopenharmony_ci}; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cienum { 7308c2ecf20Sopenharmony_ci Opt_err_cont, Opt_err_panic, Opt_err_ro, 7318c2ecf20Sopenharmony_ci Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery, 7328c2ecf20Sopenharmony_ci Opt_discard, Opt_nodiscard, Opt_err, 7338c2ecf20Sopenharmony_ci}; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic match_table_t tokens = { 7368c2ecf20Sopenharmony_ci {Opt_err_cont, "errors=continue"}, 7378c2ecf20Sopenharmony_ci {Opt_err_panic, "errors=panic"}, 7388c2ecf20Sopenharmony_ci {Opt_err_ro, "errors=remount-ro"}, 7398c2ecf20Sopenharmony_ci {Opt_barrier, "barrier"}, 7408c2ecf20Sopenharmony_ci {Opt_nobarrier, "nobarrier"}, 7418c2ecf20Sopenharmony_ci {Opt_snapshot, "cp=%u"}, 7428c2ecf20Sopenharmony_ci {Opt_order, "order=%s"}, 7438c2ecf20Sopenharmony_ci {Opt_norecovery, "norecovery"}, 7448c2ecf20Sopenharmony_ci {Opt_discard, "discard"}, 7458c2ecf20Sopenharmony_ci {Opt_nodiscard, "nodiscard"}, 7468c2ecf20Sopenharmony_ci {Opt_err, NULL} 7478c2ecf20Sopenharmony_ci}; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic int parse_options(char *options, struct super_block *sb, int is_remount) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 7528c2ecf20Sopenharmony_ci char *p; 7538c2ecf20Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (!options) 7568c2ecf20Sopenharmony_ci return 1; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 7598c2ecf20Sopenharmony_ci int token; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!*p) 7628c2ecf20Sopenharmony_ci continue; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci token = match_token(p, tokens, args); 7658c2ecf20Sopenharmony_ci switch (token) { 7668c2ecf20Sopenharmony_ci case Opt_barrier: 7678c2ecf20Sopenharmony_ci nilfs_set_opt(nilfs, BARRIER); 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci case Opt_nobarrier: 7708c2ecf20Sopenharmony_ci nilfs_clear_opt(nilfs, BARRIER); 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci case Opt_order: 7738c2ecf20Sopenharmony_ci if (strcmp(args[0].from, "relaxed") == 0) 7748c2ecf20Sopenharmony_ci /* Ordered data semantics */ 7758c2ecf20Sopenharmony_ci nilfs_clear_opt(nilfs, STRICT_ORDER); 7768c2ecf20Sopenharmony_ci else if (strcmp(args[0].from, "strict") == 0) 7778c2ecf20Sopenharmony_ci /* Strict in-order semantics */ 7788c2ecf20Sopenharmony_ci nilfs_set_opt(nilfs, STRICT_ORDER); 7798c2ecf20Sopenharmony_ci else 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci case Opt_err_panic: 7838c2ecf20Sopenharmony_ci nilfs_write_opt(nilfs, ERROR_MODE, ERRORS_PANIC); 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci case Opt_err_ro: 7868c2ecf20Sopenharmony_ci nilfs_write_opt(nilfs, ERROR_MODE, ERRORS_RO); 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci case Opt_err_cont: 7898c2ecf20Sopenharmony_ci nilfs_write_opt(nilfs, ERROR_MODE, ERRORS_CONT); 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci case Opt_snapshot: 7928c2ecf20Sopenharmony_ci if (is_remount) { 7938c2ecf20Sopenharmony_ci nilfs_err(sb, 7948c2ecf20Sopenharmony_ci "\"%s\" option is invalid for remount", 7958c2ecf20Sopenharmony_ci p); 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci case Opt_norecovery: 8008c2ecf20Sopenharmony_ci nilfs_set_opt(nilfs, NORECOVERY); 8018c2ecf20Sopenharmony_ci break; 8028c2ecf20Sopenharmony_ci case Opt_discard: 8038c2ecf20Sopenharmony_ci nilfs_set_opt(nilfs, DISCARD); 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci case Opt_nodiscard: 8068c2ecf20Sopenharmony_ci nilfs_clear_opt(nilfs, DISCARD); 8078c2ecf20Sopenharmony_ci break; 8088c2ecf20Sopenharmony_ci default: 8098c2ecf20Sopenharmony_ci nilfs_err(sb, "unrecognized mount option \"%s\"", p); 8108c2ecf20Sopenharmony_ci return 0; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci return 1; 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic inline void 8178c2ecf20Sopenharmony_cinilfs_set_default_options(struct super_block *sb, 8188c2ecf20Sopenharmony_ci struct nilfs_super_block *sbp) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci nilfs->ns_mount_opt = 8238c2ecf20Sopenharmony_ci NILFS_MOUNT_ERRORS_RO | NILFS_MOUNT_BARRIER; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic int nilfs_setup_super(struct super_block *sb, int is_mount) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 8298c2ecf20Sopenharmony_ci struct nilfs_super_block **sbp; 8308c2ecf20Sopenharmony_ci int max_mnt_count; 8318c2ecf20Sopenharmony_ci int mnt_count; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* nilfs->ns_sem must be locked by the caller. */ 8348c2ecf20Sopenharmony_ci sbp = nilfs_prepare_super(sb, 0); 8358c2ecf20Sopenharmony_ci if (!sbp) 8368c2ecf20Sopenharmony_ci return -EIO; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (!is_mount) 8398c2ecf20Sopenharmony_ci goto skip_mount_setup; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci max_mnt_count = le16_to_cpu(sbp[0]->s_max_mnt_count); 8428c2ecf20Sopenharmony_ci mnt_count = le16_to_cpu(sbp[0]->s_mnt_count); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (nilfs->ns_mount_state & NILFS_ERROR_FS) { 8458c2ecf20Sopenharmony_ci nilfs_warn(sb, "mounting fs with errors"); 8468c2ecf20Sopenharmony_ci#if 0 8478c2ecf20Sopenharmony_ci } else if (max_mnt_count >= 0 && mnt_count >= max_mnt_count) { 8488c2ecf20Sopenharmony_ci nilfs_warn(sb, "maximal mount count reached"); 8498c2ecf20Sopenharmony_ci#endif 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci if (!max_mnt_count) 8528c2ecf20Sopenharmony_ci sbp[0]->s_max_mnt_count = cpu_to_le16(NILFS_DFL_MAX_MNT_COUNT); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci sbp[0]->s_mnt_count = cpu_to_le16(mnt_count + 1); 8558c2ecf20Sopenharmony_ci sbp[0]->s_mtime = cpu_to_le64(ktime_get_real_seconds()); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ciskip_mount_setup: 8588c2ecf20Sopenharmony_ci sbp[0]->s_state = 8598c2ecf20Sopenharmony_ci cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS); 8608c2ecf20Sopenharmony_ci /* synchronize sbp[1] with sbp[0] */ 8618c2ecf20Sopenharmony_ci if (sbp[1]) 8628c2ecf20Sopenharmony_ci memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); 8638c2ecf20Sopenharmony_ci return nilfs_commit_super(sb, NILFS_SB_COMMIT_ALL); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistruct nilfs_super_block *nilfs_read_super_block(struct super_block *sb, 8678c2ecf20Sopenharmony_ci u64 pos, int blocksize, 8688c2ecf20Sopenharmony_ci struct buffer_head **pbh) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci unsigned long long sb_index = pos; 8718c2ecf20Sopenharmony_ci unsigned long offset; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci offset = do_div(sb_index, blocksize); 8748c2ecf20Sopenharmony_ci *pbh = sb_bread(sb, sb_index); 8758c2ecf20Sopenharmony_ci if (!*pbh) 8768c2ecf20Sopenharmony_ci return NULL; 8778c2ecf20Sopenharmony_ci return (struct nilfs_super_block *)((char *)(*pbh)->b_data + offset); 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ciint nilfs_store_magic_and_option(struct super_block *sb, 8818c2ecf20Sopenharmony_ci struct nilfs_super_block *sbp, 8828c2ecf20Sopenharmony_ci char *data) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci sb->s_magic = le16_to_cpu(sbp->s_magic); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* FS independent flags */ 8898c2ecf20Sopenharmony_ci#ifdef NILFS_ATIME_DISABLE 8908c2ecf20Sopenharmony_ci sb->s_flags |= SB_NOATIME; 8918c2ecf20Sopenharmony_ci#endif 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci nilfs_set_default_options(sb, sbp); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci nilfs->ns_resuid = le16_to_cpu(sbp->s_def_resuid); 8968c2ecf20Sopenharmony_ci nilfs->ns_resgid = le16_to_cpu(sbp->s_def_resgid); 8978c2ecf20Sopenharmony_ci nilfs->ns_interval = le32_to_cpu(sbp->s_c_interval); 8988c2ecf20Sopenharmony_ci nilfs->ns_watermark = le32_to_cpu(sbp->s_c_block_max); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci return !parse_options(data, sb, 0) ? -EINVAL : 0; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ciint nilfs_check_feature_compatibility(struct super_block *sb, 9048c2ecf20Sopenharmony_ci struct nilfs_super_block *sbp) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci __u64 features; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci features = le64_to_cpu(sbp->s_feature_incompat) & 9098c2ecf20Sopenharmony_ci ~NILFS_FEATURE_INCOMPAT_SUPP; 9108c2ecf20Sopenharmony_ci if (features) { 9118c2ecf20Sopenharmony_ci nilfs_err(sb, 9128c2ecf20Sopenharmony_ci "couldn't mount because of unsupported optional features (%llx)", 9138c2ecf20Sopenharmony_ci (unsigned long long)features); 9148c2ecf20Sopenharmony_ci return -EINVAL; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci features = le64_to_cpu(sbp->s_feature_compat_ro) & 9178c2ecf20Sopenharmony_ci ~NILFS_FEATURE_COMPAT_RO_SUPP; 9188c2ecf20Sopenharmony_ci if (!sb_rdonly(sb) && features) { 9198c2ecf20Sopenharmony_ci nilfs_err(sb, 9208c2ecf20Sopenharmony_ci "couldn't mount RDWR because of unsupported optional features (%llx)", 9218c2ecf20Sopenharmony_ci (unsigned long long)features); 9228c2ecf20Sopenharmony_ci return -EINVAL; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci return 0; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic int nilfs_get_root_dentry(struct super_block *sb, 9288c2ecf20Sopenharmony_ci struct nilfs_root *root, 9298c2ecf20Sopenharmony_ci struct dentry **root_dentry) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct inode *inode; 9328c2ecf20Sopenharmony_ci struct dentry *dentry; 9338c2ecf20Sopenharmony_ci int ret = 0; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci inode = nilfs_iget(sb, root, NILFS_ROOT_INO); 9368c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 9378c2ecf20Sopenharmony_ci ret = PTR_ERR(inode); 9388c2ecf20Sopenharmony_ci nilfs_err(sb, "error %d getting root inode", ret); 9398c2ecf20Sopenharmony_ci goto out; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci if (!S_ISDIR(inode->i_mode) || !inode->i_blocks || !inode->i_size) { 9428c2ecf20Sopenharmony_ci iput(inode); 9438c2ecf20Sopenharmony_ci nilfs_err(sb, "corrupt root inode"); 9448c2ecf20Sopenharmony_ci ret = -EINVAL; 9458c2ecf20Sopenharmony_ci goto out; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (root->cno == NILFS_CPTREE_CURRENT_CNO) { 9498c2ecf20Sopenharmony_ci dentry = d_find_alias(inode); 9508c2ecf20Sopenharmony_ci if (!dentry) { 9518c2ecf20Sopenharmony_ci dentry = d_make_root(inode); 9528c2ecf20Sopenharmony_ci if (!dentry) { 9538c2ecf20Sopenharmony_ci ret = -ENOMEM; 9548c2ecf20Sopenharmony_ci goto failed_dentry; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci } else { 9578c2ecf20Sopenharmony_ci iput(inode); 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci } else { 9608c2ecf20Sopenharmony_ci dentry = d_obtain_root(inode); 9618c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) { 9628c2ecf20Sopenharmony_ci ret = PTR_ERR(dentry); 9638c2ecf20Sopenharmony_ci goto failed_dentry; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci *root_dentry = dentry; 9678c2ecf20Sopenharmony_ci out: 9688c2ecf20Sopenharmony_ci return ret; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci failed_dentry: 9718c2ecf20Sopenharmony_ci nilfs_err(sb, "error %d getting root dentry", ret); 9728c2ecf20Sopenharmony_ci goto out; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic int nilfs_attach_snapshot(struct super_block *s, __u64 cno, 9768c2ecf20Sopenharmony_ci struct dentry **root_dentry) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = s->s_fs_info; 9798c2ecf20Sopenharmony_ci struct nilfs_root *root; 9808c2ecf20Sopenharmony_ci int ret; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci mutex_lock(&nilfs->ns_snapshot_mount_mutex); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci down_read(&nilfs->ns_segctor_sem); 9858c2ecf20Sopenharmony_ci ret = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, cno); 9868c2ecf20Sopenharmony_ci up_read(&nilfs->ns_segctor_sem); 9878c2ecf20Sopenharmony_ci if (ret < 0) { 9888c2ecf20Sopenharmony_ci ret = (ret == -ENOENT) ? -EINVAL : ret; 9898c2ecf20Sopenharmony_ci goto out; 9908c2ecf20Sopenharmony_ci } else if (!ret) { 9918c2ecf20Sopenharmony_ci nilfs_err(s, 9928c2ecf20Sopenharmony_ci "The specified checkpoint is not a snapshot (checkpoint number=%llu)", 9938c2ecf20Sopenharmony_ci (unsigned long long)cno); 9948c2ecf20Sopenharmony_ci ret = -EINVAL; 9958c2ecf20Sopenharmony_ci goto out; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci ret = nilfs_attach_checkpoint(s, cno, false, &root); 9998c2ecf20Sopenharmony_ci if (ret) { 10008c2ecf20Sopenharmony_ci nilfs_err(s, 10018c2ecf20Sopenharmony_ci "error %d while loading snapshot (checkpoint number=%llu)", 10028c2ecf20Sopenharmony_ci ret, (unsigned long long)cno); 10038c2ecf20Sopenharmony_ci goto out; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci ret = nilfs_get_root_dentry(s, root, root_dentry); 10068c2ecf20Sopenharmony_ci nilfs_put_root(root); 10078c2ecf20Sopenharmony_ci out: 10088c2ecf20Sopenharmony_ci mutex_unlock(&nilfs->ns_snapshot_mount_mutex); 10098c2ecf20Sopenharmony_ci return ret; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/** 10138c2ecf20Sopenharmony_ci * nilfs_tree_is_busy() - try to shrink dentries of a checkpoint 10148c2ecf20Sopenharmony_ci * @root_dentry: root dentry of the tree to be shrunk 10158c2ecf20Sopenharmony_ci * 10168c2ecf20Sopenharmony_ci * This function returns true if the tree was in-use. 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_cistatic bool nilfs_tree_is_busy(struct dentry *root_dentry) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci shrink_dcache_parent(root_dentry); 10218c2ecf20Sopenharmony_ci return d_count(root_dentry) > 1; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ciint nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 10278c2ecf20Sopenharmony_ci struct nilfs_root *root; 10288c2ecf20Sopenharmony_ci struct inode *inode; 10298c2ecf20Sopenharmony_ci struct dentry *dentry; 10308c2ecf20Sopenharmony_ci int ret; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (cno > nilfs->ns_cno) 10338c2ecf20Sopenharmony_ci return false; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (cno >= nilfs_last_cno(nilfs)) 10368c2ecf20Sopenharmony_ci return true; /* protect recent checkpoints */ 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci ret = false; 10398c2ecf20Sopenharmony_ci root = nilfs_lookup_root(nilfs, cno); 10408c2ecf20Sopenharmony_ci if (root) { 10418c2ecf20Sopenharmony_ci inode = nilfs_ilookup(sb, root, NILFS_ROOT_INO); 10428c2ecf20Sopenharmony_ci if (inode) { 10438c2ecf20Sopenharmony_ci dentry = d_find_alias(inode); 10448c2ecf20Sopenharmony_ci if (dentry) { 10458c2ecf20Sopenharmony_ci ret = nilfs_tree_is_busy(dentry); 10468c2ecf20Sopenharmony_ci dput(dentry); 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci iput(inode); 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci nilfs_put_root(root); 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci return ret; 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci/** 10568c2ecf20Sopenharmony_ci * nilfs_fill_super() - initialize a super block instance 10578c2ecf20Sopenharmony_ci * @sb: super_block 10588c2ecf20Sopenharmony_ci * @data: mount options 10598c2ecf20Sopenharmony_ci * @silent: silent mode flag 10608c2ecf20Sopenharmony_ci * 10618c2ecf20Sopenharmony_ci * This function is called exclusively by nilfs->ns_mount_mutex. 10628c2ecf20Sopenharmony_ci * So, the recovery process is protected from other simultaneous mounts. 10638c2ecf20Sopenharmony_ci */ 10648c2ecf20Sopenharmony_cistatic int 10658c2ecf20Sopenharmony_cinilfs_fill_super(struct super_block *sb, void *data, int silent) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci struct the_nilfs *nilfs; 10688c2ecf20Sopenharmony_ci struct nilfs_root *fsroot; 10698c2ecf20Sopenharmony_ci __u64 cno; 10708c2ecf20Sopenharmony_ci int err; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci nilfs = alloc_nilfs(sb); 10738c2ecf20Sopenharmony_ci if (!nilfs) 10748c2ecf20Sopenharmony_ci return -ENOMEM; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci sb->s_fs_info = nilfs; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci err = init_nilfs(nilfs, sb, (char *)data); 10798c2ecf20Sopenharmony_ci if (err) 10808c2ecf20Sopenharmony_ci goto failed_nilfs; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci sb->s_op = &nilfs_sops; 10838c2ecf20Sopenharmony_ci sb->s_export_op = &nilfs_export_ops; 10848c2ecf20Sopenharmony_ci sb->s_root = NULL; 10858c2ecf20Sopenharmony_ci sb->s_time_gran = 1; 10868c2ecf20Sopenharmony_ci sb->s_max_links = NILFS_LINK_MAX; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci sb->s_bdi = bdi_get(sb->s_bdev->bd_bdi); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci err = load_nilfs(nilfs, sb); 10918c2ecf20Sopenharmony_ci if (err) 10928c2ecf20Sopenharmony_ci goto failed_nilfs; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci cno = nilfs_last_cno(nilfs); 10958c2ecf20Sopenharmony_ci err = nilfs_attach_checkpoint(sb, cno, true, &fsroot); 10968c2ecf20Sopenharmony_ci if (err) { 10978c2ecf20Sopenharmony_ci nilfs_err(sb, 10988c2ecf20Sopenharmony_ci "error %d while loading last checkpoint (checkpoint number=%llu)", 10998c2ecf20Sopenharmony_ci err, (unsigned long long)cno); 11008c2ecf20Sopenharmony_ci goto failed_unload; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 11048c2ecf20Sopenharmony_ci err = nilfs_attach_log_writer(sb, fsroot); 11058c2ecf20Sopenharmony_ci if (err) 11068c2ecf20Sopenharmony_ci goto failed_checkpoint; 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci err = nilfs_get_root_dentry(sb, fsroot, &sb->s_root); 11108c2ecf20Sopenharmony_ci if (err) 11118c2ecf20Sopenharmony_ci goto failed_segctor; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci nilfs_put_root(fsroot); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 11168c2ecf20Sopenharmony_ci down_write(&nilfs->ns_sem); 11178c2ecf20Sopenharmony_ci nilfs_setup_super(sb, true); 11188c2ecf20Sopenharmony_ci up_write(&nilfs->ns_sem); 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci return 0; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci failed_segctor: 11248c2ecf20Sopenharmony_ci nilfs_detach_log_writer(sb); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci failed_checkpoint: 11278c2ecf20Sopenharmony_ci nilfs_put_root(fsroot); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci failed_unload: 11308c2ecf20Sopenharmony_ci nilfs_sysfs_delete_device_group(nilfs); 11318c2ecf20Sopenharmony_ci iput(nilfs->ns_sufile); 11328c2ecf20Sopenharmony_ci iput(nilfs->ns_cpfile); 11338c2ecf20Sopenharmony_ci iput(nilfs->ns_dat); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci failed_nilfs: 11368c2ecf20Sopenharmony_ci destroy_nilfs(nilfs); 11378c2ecf20Sopenharmony_ci return err; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistatic int nilfs_remount(struct super_block *sb, int *flags, char *data) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci struct the_nilfs *nilfs = sb->s_fs_info; 11438c2ecf20Sopenharmony_ci unsigned long old_sb_flags; 11448c2ecf20Sopenharmony_ci unsigned long old_mount_opt; 11458c2ecf20Sopenharmony_ci int err; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci sync_filesystem(sb); 11488c2ecf20Sopenharmony_ci old_sb_flags = sb->s_flags; 11498c2ecf20Sopenharmony_ci old_mount_opt = nilfs->ns_mount_opt; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (!parse_options(data, sb, 1)) { 11528c2ecf20Sopenharmony_ci err = -EINVAL; 11538c2ecf20Sopenharmony_ci goto restore_opts; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci sb->s_flags = (sb->s_flags & ~SB_POSIXACL); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci err = -EINVAL; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (!nilfs_valid_fs(nilfs)) { 11608c2ecf20Sopenharmony_ci nilfs_warn(sb, 11618c2ecf20Sopenharmony_ci "couldn't remount because the filesystem is in an incomplete recovery state"); 11628c2ecf20Sopenharmony_ci goto restore_opts; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb)) 11668c2ecf20Sopenharmony_ci goto out; 11678c2ecf20Sopenharmony_ci if (*flags & SB_RDONLY) { 11688c2ecf20Sopenharmony_ci sb->s_flags |= SB_RDONLY; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* 11718c2ecf20Sopenharmony_ci * Remounting a valid RW partition RDONLY, so set 11728c2ecf20Sopenharmony_ci * the RDONLY flag and then mark the partition as valid again. 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_ci down_write(&nilfs->ns_sem); 11758c2ecf20Sopenharmony_ci nilfs_cleanup_super(sb); 11768c2ecf20Sopenharmony_ci up_write(&nilfs->ns_sem); 11778c2ecf20Sopenharmony_ci } else { 11788c2ecf20Sopenharmony_ci __u64 features; 11798c2ecf20Sopenharmony_ci struct nilfs_root *root; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* 11828c2ecf20Sopenharmony_ci * Mounting a RDONLY partition read-write, so reread and 11838c2ecf20Sopenharmony_ci * store the current valid flag. (It may have been changed 11848c2ecf20Sopenharmony_ci * by fsck since we originally mounted the partition.) 11858c2ecf20Sopenharmony_ci */ 11868c2ecf20Sopenharmony_ci down_read(&nilfs->ns_sem); 11878c2ecf20Sopenharmony_ci features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) & 11888c2ecf20Sopenharmony_ci ~NILFS_FEATURE_COMPAT_RO_SUPP; 11898c2ecf20Sopenharmony_ci up_read(&nilfs->ns_sem); 11908c2ecf20Sopenharmony_ci if (features) { 11918c2ecf20Sopenharmony_ci nilfs_warn(sb, 11928c2ecf20Sopenharmony_ci "couldn't remount RDWR because of unsupported optional features (%llx)", 11938c2ecf20Sopenharmony_ci (unsigned long long)features); 11948c2ecf20Sopenharmony_ci err = -EROFS; 11958c2ecf20Sopenharmony_ci goto restore_opts; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci sb->s_flags &= ~SB_RDONLY; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci root = NILFS_I(d_inode(sb->s_root))->i_root; 12018c2ecf20Sopenharmony_ci err = nilfs_attach_log_writer(sb, root); 12028c2ecf20Sopenharmony_ci if (err) 12038c2ecf20Sopenharmony_ci goto restore_opts; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci down_write(&nilfs->ns_sem); 12068c2ecf20Sopenharmony_ci nilfs_setup_super(sb, true); 12078c2ecf20Sopenharmony_ci up_write(&nilfs->ns_sem); 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci out: 12108c2ecf20Sopenharmony_ci return 0; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci restore_opts: 12138c2ecf20Sopenharmony_ci sb->s_flags = old_sb_flags; 12148c2ecf20Sopenharmony_ci nilfs->ns_mount_opt = old_mount_opt; 12158c2ecf20Sopenharmony_ci return err; 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_cistruct nilfs_super_data { 12198c2ecf20Sopenharmony_ci struct block_device *bdev; 12208c2ecf20Sopenharmony_ci __u64 cno; 12218c2ecf20Sopenharmony_ci int flags; 12228c2ecf20Sopenharmony_ci}; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic int nilfs_parse_snapshot_option(const char *option, 12258c2ecf20Sopenharmony_ci const substring_t *arg, 12268c2ecf20Sopenharmony_ci struct nilfs_super_data *sd) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci unsigned long long val; 12298c2ecf20Sopenharmony_ci const char *msg = NULL; 12308c2ecf20Sopenharmony_ci int err; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (!(sd->flags & SB_RDONLY)) { 12338c2ecf20Sopenharmony_ci msg = "read-only option is not specified"; 12348c2ecf20Sopenharmony_ci goto parse_error; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci err = kstrtoull(arg->from, 0, &val); 12388c2ecf20Sopenharmony_ci if (err) { 12398c2ecf20Sopenharmony_ci if (err == -ERANGE) 12408c2ecf20Sopenharmony_ci msg = "too large checkpoint number"; 12418c2ecf20Sopenharmony_ci else 12428c2ecf20Sopenharmony_ci msg = "malformed argument"; 12438c2ecf20Sopenharmony_ci goto parse_error; 12448c2ecf20Sopenharmony_ci } else if (val == 0) { 12458c2ecf20Sopenharmony_ci msg = "invalid checkpoint number 0"; 12468c2ecf20Sopenharmony_ci goto parse_error; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci sd->cno = val; 12498c2ecf20Sopenharmony_ci return 0; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ciparse_error: 12528c2ecf20Sopenharmony_ci nilfs_err(NULL, "invalid option \"%s\": %s", option, msg); 12538c2ecf20Sopenharmony_ci return 1; 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci/** 12578c2ecf20Sopenharmony_ci * nilfs_identify - pre-read mount options needed to identify mount instance 12588c2ecf20Sopenharmony_ci * @data: mount options 12598c2ecf20Sopenharmony_ci * @sd: nilfs_super_data 12608c2ecf20Sopenharmony_ci */ 12618c2ecf20Sopenharmony_cistatic int nilfs_identify(char *data, struct nilfs_super_data *sd) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci char *p, *options = data; 12648c2ecf20Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 12658c2ecf20Sopenharmony_ci int token; 12668c2ecf20Sopenharmony_ci int ret = 0; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci do { 12698c2ecf20Sopenharmony_ci p = strsep(&options, ","); 12708c2ecf20Sopenharmony_ci if (p != NULL && *p) { 12718c2ecf20Sopenharmony_ci token = match_token(p, tokens, args); 12728c2ecf20Sopenharmony_ci if (token == Opt_snapshot) 12738c2ecf20Sopenharmony_ci ret = nilfs_parse_snapshot_option(p, &args[0], 12748c2ecf20Sopenharmony_ci sd); 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci if (!options) 12778c2ecf20Sopenharmony_ci break; 12788c2ecf20Sopenharmony_ci BUG_ON(options == data); 12798c2ecf20Sopenharmony_ci *(options - 1) = ','; 12808c2ecf20Sopenharmony_ci } while (!ret); 12818c2ecf20Sopenharmony_ci return ret; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_cistatic int nilfs_set_bdev_super(struct super_block *s, void *data) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci s->s_bdev = data; 12878c2ecf20Sopenharmony_ci s->s_dev = s->s_bdev->bd_dev; 12888c2ecf20Sopenharmony_ci return 0; 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistatic int nilfs_test_bdev_super(struct super_block *s, void *data) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci return (void *)s->s_bdev == data; 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cistatic struct dentry * 12978c2ecf20Sopenharmony_cinilfs_mount(struct file_system_type *fs_type, int flags, 12988c2ecf20Sopenharmony_ci const char *dev_name, void *data) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci struct nilfs_super_data sd; 13018c2ecf20Sopenharmony_ci struct super_block *s; 13028c2ecf20Sopenharmony_ci fmode_t mode = FMODE_READ | FMODE_EXCL; 13038c2ecf20Sopenharmony_ci struct dentry *root_dentry; 13048c2ecf20Sopenharmony_ci int err, s_new = false; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci if (!(flags & SB_RDONLY)) 13078c2ecf20Sopenharmony_ci mode |= FMODE_WRITE; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci sd.bdev = blkdev_get_by_path(dev_name, mode, fs_type); 13108c2ecf20Sopenharmony_ci if (IS_ERR(sd.bdev)) 13118c2ecf20Sopenharmony_ci return ERR_CAST(sd.bdev); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci sd.cno = 0; 13148c2ecf20Sopenharmony_ci sd.flags = flags; 13158c2ecf20Sopenharmony_ci if (nilfs_identify((char *)data, &sd)) { 13168c2ecf20Sopenharmony_ci err = -EINVAL; 13178c2ecf20Sopenharmony_ci goto failed; 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* 13218c2ecf20Sopenharmony_ci * once the super is inserted into the list by sget, s_umount 13228c2ecf20Sopenharmony_ci * will protect the lockfs code from trying to start a snapshot 13238c2ecf20Sopenharmony_ci * while we are mounting 13248c2ecf20Sopenharmony_ci */ 13258c2ecf20Sopenharmony_ci mutex_lock(&sd.bdev->bd_fsfreeze_mutex); 13268c2ecf20Sopenharmony_ci if (sd.bdev->bd_fsfreeze_count > 0) { 13278c2ecf20Sopenharmony_ci mutex_unlock(&sd.bdev->bd_fsfreeze_mutex); 13288c2ecf20Sopenharmony_ci err = -EBUSY; 13298c2ecf20Sopenharmony_ci goto failed; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, flags, 13328c2ecf20Sopenharmony_ci sd.bdev); 13338c2ecf20Sopenharmony_ci mutex_unlock(&sd.bdev->bd_fsfreeze_mutex); 13348c2ecf20Sopenharmony_ci if (IS_ERR(s)) { 13358c2ecf20Sopenharmony_ci err = PTR_ERR(s); 13368c2ecf20Sopenharmony_ci goto failed; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci if (!s->s_root) { 13408c2ecf20Sopenharmony_ci s_new = true; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci /* New superblock instance created */ 13438c2ecf20Sopenharmony_ci s->s_mode = mode; 13448c2ecf20Sopenharmony_ci snprintf(s->s_id, sizeof(s->s_id), "%pg", sd.bdev); 13458c2ecf20Sopenharmony_ci sb_set_blocksize(s, block_size(sd.bdev)); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci err = nilfs_fill_super(s, data, flags & SB_SILENT ? 1 : 0); 13488c2ecf20Sopenharmony_ci if (err) 13498c2ecf20Sopenharmony_ci goto failed_super; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci s->s_flags |= SB_ACTIVE; 13528c2ecf20Sopenharmony_ci } else if (!sd.cno) { 13538c2ecf20Sopenharmony_ci if (nilfs_tree_is_busy(s->s_root)) { 13548c2ecf20Sopenharmony_ci if ((flags ^ s->s_flags) & SB_RDONLY) { 13558c2ecf20Sopenharmony_ci nilfs_err(s, 13568c2ecf20Sopenharmony_ci "the device already has a %s mount.", 13578c2ecf20Sopenharmony_ci sb_rdonly(s) ? "read-only" : "read/write"); 13588c2ecf20Sopenharmony_ci err = -EBUSY; 13598c2ecf20Sopenharmony_ci goto failed_super; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci } else { 13628c2ecf20Sopenharmony_ci /* 13638c2ecf20Sopenharmony_ci * Try remount to setup mount states if the current 13648c2ecf20Sopenharmony_ci * tree is not mounted and only snapshots use this sb. 13658c2ecf20Sopenharmony_ci */ 13668c2ecf20Sopenharmony_ci err = nilfs_remount(s, &flags, data); 13678c2ecf20Sopenharmony_ci if (err) 13688c2ecf20Sopenharmony_ci goto failed_super; 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (sd.cno) { 13738c2ecf20Sopenharmony_ci err = nilfs_attach_snapshot(s, sd.cno, &root_dentry); 13748c2ecf20Sopenharmony_ci if (err) 13758c2ecf20Sopenharmony_ci goto failed_super; 13768c2ecf20Sopenharmony_ci } else { 13778c2ecf20Sopenharmony_ci root_dentry = dget(s->s_root); 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (!s_new) 13818c2ecf20Sopenharmony_ci blkdev_put(sd.bdev, mode); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci return root_dentry; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci failed_super: 13868c2ecf20Sopenharmony_ci deactivate_locked_super(s); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci failed: 13898c2ecf20Sopenharmony_ci if (!s_new) 13908c2ecf20Sopenharmony_ci blkdev_put(sd.bdev, mode); 13918c2ecf20Sopenharmony_ci return ERR_PTR(err); 13928c2ecf20Sopenharmony_ci} 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_cistruct file_system_type nilfs_fs_type = { 13958c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 13968c2ecf20Sopenharmony_ci .name = "nilfs2", 13978c2ecf20Sopenharmony_ci .mount = nilfs_mount, 13988c2ecf20Sopenharmony_ci .kill_sb = kill_block_super, 13998c2ecf20Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 14008c2ecf20Sopenharmony_ci}; 14018c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("nilfs2"); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_cistatic void nilfs_inode_init_once(void *obj) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci struct nilfs_inode_info *ii = obj; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ii->i_dirty); 14088c2ecf20Sopenharmony_ci#ifdef CONFIG_NILFS_XATTR 14098c2ecf20Sopenharmony_ci init_rwsem(&ii->xattr_sem); 14108c2ecf20Sopenharmony_ci#endif 14118c2ecf20Sopenharmony_ci inode_init_once(&ii->vfs_inode); 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_cistatic void nilfs_segbuf_init_once(void *obj) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci memset(obj, 0, sizeof(struct nilfs_segment_buffer)); 14178c2ecf20Sopenharmony_ci} 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_cistatic void nilfs_destroy_cachep(void) 14208c2ecf20Sopenharmony_ci{ 14218c2ecf20Sopenharmony_ci /* 14228c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 14238c2ecf20Sopenharmony_ci * destroy cache. 14248c2ecf20Sopenharmony_ci */ 14258c2ecf20Sopenharmony_ci rcu_barrier(); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci kmem_cache_destroy(nilfs_inode_cachep); 14288c2ecf20Sopenharmony_ci kmem_cache_destroy(nilfs_transaction_cachep); 14298c2ecf20Sopenharmony_ci kmem_cache_destroy(nilfs_segbuf_cachep); 14308c2ecf20Sopenharmony_ci kmem_cache_destroy(nilfs_btree_path_cache); 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_cistatic int __init nilfs_init_cachep(void) 14348c2ecf20Sopenharmony_ci{ 14358c2ecf20Sopenharmony_ci nilfs_inode_cachep = kmem_cache_create("nilfs2_inode_cache", 14368c2ecf20Sopenharmony_ci sizeof(struct nilfs_inode_info), 0, 14378c2ecf20Sopenharmony_ci SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT, 14388c2ecf20Sopenharmony_ci nilfs_inode_init_once); 14398c2ecf20Sopenharmony_ci if (!nilfs_inode_cachep) 14408c2ecf20Sopenharmony_ci goto fail; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci nilfs_transaction_cachep = kmem_cache_create("nilfs2_transaction_cache", 14438c2ecf20Sopenharmony_ci sizeof(struct nilfs_transaction_info), 0, 14448c2ecf20Sopenharmony_ci SLAB_RECLAIM_ACCOUNT, NULL); 14458c2ecf20Sopenharmony_ci if (!nilfs_transaction_cachep) 14468c2ecf20Sopenharmony_ci goto fail; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci nilfs_segbuf_cachep = kmem_cache_create("nilfs2_segbuf_cache", 14498c2ecf20Sopenharmony_ci sizeof(struct nilfs_segment_buffer), 0, 14508c2ecf20Sopenharmony_ci SLAB_RECLAIM_ACCOUNT, nilfs_segbuf_init_once); 14518c2ecf20Sopenharmony_ci if (!nilfs_segbuf_cachep) 14528c2ecf20Sopenharmony_ci goto fail; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci nilfs_btree_path_cache = kmem_cache_create("nilfs2_btree_path_cache", 14558c2ecf20Sopenharmony_ci sizeof(struct nilfs_btree_path) * NILFS_BTREE_LEVEL_MAX, 14568c2ecf20Sopenharmony_ci 0, 0, NULL); 14578c2ecf20Sopenharmony_ci if (!nilfs_btree_path_cache) 14588c2ecf20Sopenharmony_ci goto fail; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci return 0; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_cifail: 14638c2ecf20Sopenharmony_ci nilfs_destroy_cachep(); 14648c2ecf20Sopenharmony_ci return -ENOMEM; 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic int __init init_nilfs_fs(void) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci int err; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci err = nilfs_init_cachep(); 14728c2ecf20Sopenharmony_ci if (err) 14738c2ecf20Sopenharmony_ci goto fail; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci err = nilfs_sysfs_init(); 14768c2ecf20Sopenharmony_ci if (err) 14778c2ecf20Sopenharmony_ci goto free_cachep; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci err = register_filesystem(&nilfs_fs_type); 14808c2ecf20Sopenharmony_ci if (err) 14818c2ecf20Sopenharmony_ci goto deinit_sysfs_entry; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci printk(KERN_INFO "NILFS version 2 loaded\n"); 14848c2ecf20Sopenharmony_ci return 0; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_cideinit_sysfs_entry: 14878c2ecf20Sopenharmony_ci nilfs_sysfs_exit(); 14888c2ecf20Sopenharmony_cifree_cachep: 14898c2ecf20Sopenharmony_ci nilfs_destroy_cachep(); 14908c2ecf20Sopenharmony_cifail: 14918c2ecf20Sopenharmony_ci return err; 14928c2ecf20Sopenharmony_ci} 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_cistatic void __exit exit_nilfs_fs(void) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci nilfs_destroy_cachep(); 14978c2ecf20Sopenharmony_ci nilfs_sysfs_exit(); 14988c2ecf20Sopenharmony_ci unregister_filesystem(&nilfs_fs_type); 14998c2ecf20Sopenharmony_ci} 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cimodule_init(init_nilfs_fs) 15028c2ecf20Sopenharmony_cimodule_exit(exit_nilfs_fs) 1503