linux/fs/nilfs2/segment.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * NILFS segment constructor.
 *
 * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
 *
 * Written by Ryusuke Konishi.
 *
 */

#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include <linux/writeback.h>
#include <linux/bitops.h>
#include <linux/bio.h>
#include <linux/completion.h>
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/crc32.h>
#include <linux/pagevec.h>
#include <linux/slab.h>
#include <linux/sched/signal.h>

#include "nilfs.h"
#include "btnode.h"
#include "page.h"
#include "segment.h"
#include "sufile.h"
#include "cpfile.h"
#include "ifile.h"
#include "segbuf.h"


/*
 * Segment constructor
 */
#define SC_N_INODEVEC

#define SC_MAX_SEGDELTA

/* Construction mode */
enum {};

/* Stage numbers of dirty block collection */
enum {};

#define CREATE_TRACE_POINTS
#include <trace/events/nilfs2.h>

/*
 * nilfs_sc_cstage_inc(), nilfs_sc_cstage_set(), nilfs_sc_cstage_get() are
 * wrapper functions of stage count (nilfs_sc_info->sc_stage.scnt). Users of
 * the variable must use them because transition of stage count must involve
 * trace events (trace_nilfs2_collection_stage_transition).
 *
 * nilfs_sc_cstage_get() isn't required for the above purpose because it doesn't
 * produce tracepoint events. It is provided just for making the intention
 * clear.
 */
static inline void nilfs_sc_cstage_inc(struct nilfs_sc_info *sci)
{}

static inline void nilfs_sc_cstage_set(struct nilfs_sc_info *sci, int next_scnt)
{}

static inline int nilfs_sc_cstage_get(struct nilfs_sc_info *sci)
{}

/* State flags of collection */
#define NILFS_CF_NODE
#define NILFS_CF_IFILE_STARTED
#define NILFS_CF_SUFREED
#define NILFS_CF_HISTORY_MASK

/* Operations depending on the construction mode and file type */
struct nilfs_sc_operations {};

/*
 * Other definitions
 */
static void nilfs_segctor_start_timer(struct nilfs_sc_info *);
static void nilfs_segctor_do_flush(struct nilfs_sc_info *, int);
static void nilfs_segctor_do_immediate_flush(struct nilfs_sc_info *);
static void nilfs_dispose_list(struct the_nilfs *, struct list_head *, int);

#define nilfs_cnt32_ge(a, b)

static int nilfs_prepare_segment_lock(struct super_block *sb,
				      struct nilfs_transaction_info *ti)
{}

/**
 * nilfs_transaction_begin - start indivisible file operations.
 * @sb: super block
 * @ti: nilfs_transaction_info
 * @vacancy_check: flags for vacancy rate checks
 *
 * nilfs_transaction_begin() acquires a reader/writer semaphore, called
 * the segment semaphore, to make a segment construction and write tasks
 * exclusive.  The function is used with nilfs_transaction_commit() in pairs.
 * The region enclosed by these two functions can be nested.  To avoid a
 * deadlock, the semaphore is only acquired or released in the outermost call.
 *
 * This function allocates a nilfs_transaction_info struct to keep context
 * information on it.  It is initialized and hooked onto the current task in
 * the outermost call.  If a pre-allocated struct is given to @ti, it is used
 * instead; otherwise a new struct is assigned from a slab.
 *
 * When @vacancy_check flag is set, this function will check the amount of
 * free space, and will wait for the GC to reclaim disk space if low capacity.
 *
 * Return Value: On success, 0 is returned. On error, one of the following
 * negative error code is returned.
 *
 * %-ENOMEM - Insufficient memory available.
 *
 * %-ENOSPC - No space left on device
 */
int nilfs_transaction_begin(struct super_block *sb,
			    struct nilfs_transaction_info *ti,
			    int vacancy_check)
{}

/**
 * nilfs_transaction_commit - commit indivisible file operations.
 * @sb: super block
 *
 * nilfs_transaction_commit() releases the read semaphore which is
 * acquired by nilfs_transaction_begin(). This is only performed
 * in outermost call of this function.  If a commit flag is set,
 * nilfs_transaction_commit() sets a timer to start the segment
 * constructor.  If a sync flag is set, it starts construction
 * directly.
 */
int nilfs_transaction_commit(struct super_block *sb)
{}

void nilfs_transaction_abort(struct super_block *sb)
{}

void nilfs_relax_pressure_in_lock(struct super_block *sb)
{}

static void nilfs_transaction_lock(struct super_block *sb,
				   struct nilfs_transaction_info *ti,
				   int gcflag)
{}

static void nilfs_transaction_unlock(struct super_block *sb)
{}

static void *nilfs_segctor_map_segsum_entry(struct nilfs_sc_info *sci,
					    struct nilfs_segsum_pointer *ssp,
					    unsigned int bytes)
{}

/**
 * nilfs_segctor_reset_segment_buffer - reset the current segment buffer
 * @sci: nilfs_sc_info
 */
static int nilfs_segctor_reset_segment_buffer(struct nilfs_sc_info *sci)
{}

/**
 * nilfs_segctor_zeropad_segsum - zero pad the rest of the segment summary area
 * @sci: segment constructor object
 *
 * nilfs_segctor_zeropad_segsum() zero-fills unallocated space at the end of
 * the current segment summary block.
 */
static void nilfs_segctor_zeropad_segsum(struct nilfs_sc_info *sci)
{}

static int nilfs_segctor_feed_segment(struct nilfs_sc_info *sci)
{}

static int nilfs_segctor_add_super_root(struct nilfs_sc_info *sci)
{}

/*
 * Functions for making segment summary and payloads
 */
static int nilfs_segctor_segsum_block_required(
	struct nilfs_sc_info *sci, const struct nilfs_segsum_pointer *ssp,
	unsigned int binfo_size)
{}

static void nilfs_segctor_begin_finfo(struct nilfs_sc_info *sci,
				      struct inode *inode)
{}

static void nilfs_segctor_end_finfo(struct nilfs_sc_info *sci,
				    struct inode *inode)
{}

static int nilfs_segctor_add_file_block(struct nilfs_sc_info *sci,
					struct buffer_head *bh,
					struct inode *inode,
					unsigned int binfo_size)
{}

/*
 * Callback functions that enumerate, mark, and collect dirty blocks
 */
static int nilfs_collect_file_data(struct nilfs_sc_info *sci,
				   struct buffer_head *bh, struct inode *inode)
{}

static int nilfs_collect_file_node(struct nilfs_sc_info *sci,
				   struct buffer_head *bh,
				   struct inode *inode)
{}

static int nilfs_collect_file_bmap(struct nilfs_sc_info *sci,
				   struct buffer_head *bh,
				   struct inode *inode)
{}

static void nilfs_write_file_data_binfo(struct nilfs_sc_info *sci,
					struct nilfs_segsum_pointer *ssp,
					union nilfs_binfo *binfo)
{}

static void nilfs_write_file_node_binfo(struct nilfs_sc_info *sci,
					struct nilfs_segsum_pointer *ssp,
					union nilfs_binfo *binfo)
{}

static const struct nilfs_sc_operations nilfs_sc_file_ops =;

static int nilfs_collect_dat_data(struct nilfs_sc_info *sci,
				  struct buffer_head *bh, struct inode *inode)
{}

static int nilfs_collect_dat_bmap(struct nilfs_sc_info *sci,
				  struct buffer_head *bh, struct inode *inode)
{}

static void nilfs_write_dat_data_binfo(struct nilfs_sc_info *sci,
				       struct nilfs_segsum_pointer *ssp,
				       union nilfs_binfo *binfo)
{}

static void nilfs_write_dat_node_binfo(struct nilfs_sc_info *sci,
				       struct nilfs_segsum_pointer *ssp,
				       union nilfs_binfo *binfo)
{}

static const struct nilfs_sc_operations nilfs_sc_dat_ops =;

static const struct nilfs_sc_operations nilfs_sc_dsync_ops =;

static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode,
					      struct list_head *listp,
					      size_t nlimit,
					      loff_t start, loff_t end)
{}

static void nilfs_lookup_dirty_node_buffers(struct inode *inode,
					    struct list_head *listp)
{}

static void nilfs_dispose_list(struct the_nilfs *nilfs,
			       struct list_head *head, int force)
{}

static void nilfs_iput_work_func(struct work_struct *work)
{}

static int nilfs_test_metadata_dirty(struct the_nilfs *nilfs,
				     struct nilfs_root *root)
{}

static int nilfs_segctor_clean(struct nilfs_sc_info *sci)
{}

static int nilfs_segctor_confirm(struct nilfs_sc_info *sci)
{}

static void nilfs_segctor_clear_metadata_dirty(struct nilfs_sc_info *sci)
{}

static void nilfs_fill_in_file_bmap(struct inode *ifile,
				    struct nilfs_inode_info *ii)

{}

static void nilfs_segctor_fill_in_file_bmap(struct nilfs_sc_info *sci)
{}

/**
 * nilfs_write_root_mdt_inode - export root metadata inode information to
 *                              the on-disk inode
 * @inode:     inode object of the root metadata file
 * @raw_inode: on-disk inode
 *
 * nilfs_write_root_mdt_inode() writes inode information and bmap data of
 * @inode to the inode area of the metadata file allocated on the super root
 * block created to finalize the log.  Since super root blocks are configured
 * each time, this function zero-fills the unused area of @raw_inode.
 */
static void nilfs_write_root_mdt_inode(struct inode *inode,
				       struct nilfs_inode *raw_inode)
{}

static void nilfs_segctor_fill_in_super_root(struct nilfs_sc_info *sci,
					     struct the_nilfs *nilfs)
{}

static void nilfs_redirty_inodes(struct list_head *head)
{}

static void nilfs_drop_collected_inodes(struct list_head *head)
{}

static int nilfs_segctor_apply_buffers(struct nilfs_sc_info *sci,
				       struct inode *inode,
				       struct list_head *listp,
				       int (*collect)(struct nilfs_sc_info *,
						      struct buffer_head *,
						      struct inode *))
{}

static size_t nilfs_segctor_buffer_rest(struct nilfs_sc_info *sci)
{}

static int nilfs_segctor_scan_file(struct nilfs_sc_info *sci,
				   struct inode *inode,
				   const struct nilfs_sc_operations *sc_ops)
{}

static int nilfs_segctor_scan_file_dsync(struct nilfs_sc_info *sci,
					 struct inode *inode)
{}

static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
{}

/**
 * nilfs_segctor_begin_construction - setup segment buffer to make a new log
 * @sci: nilfs_sc_info
 * @nilfs: nilfs object
 */
static int nilfs_segctor_begin_construction(struct nilfs_sc_info *sci,
					    struct the_nilfs *nilfs)
{}

static int nilfs_segctor_extend_segments(struct nilfs_sc_info *sci,
					 struct the_nilfs *nilfs, int nadd)
{}

static void nilfs_free_incomplete_logs(struct list_head *logs,
				       struct the_nilfs *nilfs)
{}

static void nilfs_segctor_update_segusage(struct nilfs_sc_info *sci,
					  struct inode *sufile)
{}

static void nilfs_cancel_segusage(struct list_head *logs, struct inode *sufile)
{}

static void nilfs_segctor_truncate_segments(struct nilfs_sc_info *sci,
					    struct nilfs_segment_buffer *last,
					    struct inode *sufile)
{}


static int nilfs_segctor_collect(struct nilfs_sc_info *sci,
				 struct the_nilfs *nilfs, int mode)
{}

static void nilfs_list_replace_buffer(struct buffer_head *old_bh,
				      struct buffer_head *new_bh)
{}

static int
nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci,
				     struct nilfs_segment_buffer *segbuf,
				     int mode)
{}

static int nilfs_segctor_assign(struct nilfs_sc_info *sci, int mode)
{}

static void nilfs_begin_folio_io(struct folio *folio)
{}

/**
 * nilfs_prepare_write_logs - prepare to write logs
 * @logs: logs to prepare for writing
 * @seed: checksum seed value
 *
 * nilfs_prepare_write_logs() adds checksums and prepares the block
 * buffers/folios for writing logs.  In order to stabilize folios of
 * memory-mapped file blocks by putting them in writeback state before
 * calculating the checksums, first prepare to write payload blocks other
 * than segment summary and super root blocks in which the checksums will
 * be embedded.
 */
static void nilfs_prepare_write_logs(struct list_head *logs, u32 seed)
{}

static int nilfs_segctor_write(struct nilfs_sc_info *sci,
			       struct the_nilfs *nilfs)
{}

static void nilfs_end_folio_io(struct folio *folio, int err)
{}

static void nilfs_abort_logs(struct list_head *logs, int err)
{}

static void nilfs_segctor_abort_construction(struct nilfs_sc_info *sci,
					     struct the_nilfs *nilfs, int err)
{}

static void nilfs_set_next_segment(struct the_nilfs *nilfs,
				   struct nilfs_segment_buffer *segbuf)
{}

static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
{}

static int nilfs_segctor_wait(struct nilfs_sc_info *sci)
{}

static int nilfs_segctor_collect_dirty_files(struct nilfs_sc_info *sci,
					     struct the_nilfs *nilfs)
{}

static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci,
					     struct the_nilfs *nilfs)
{}

/*
 * Main procedure of segment constructor
 */
static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
{}

/**
 * nilfs_segctor_start_timer - set timer of background write
 * @sci: nilfs_sc_info
 *
 * If the timer has already been set, it ignores the new request.
 * This function MUST be called within a section locking the segment
 * semaphore.
 */
static void nilfs_segctor_start_timer(struct nilfs_sc_info *sci)
{}

static void nilfs_segctor_do_flush(struct nilfs_sc_info *sci, int bn)
{}

/**
 * nilfs_flush_segment - trigger a segment construction for resource control
 * @sb: super block
 * @ino: inode number of the file to be flushed out.
 */
void nilfs_flush_segment(struct super_block *sb, ino_t ino)
{}

struct nilfs_segctor_wait_request {};

static int nilfs_segctor_sync(struct nilfs_sc_info *sci)
{}

static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err, bool force)
{}

/**
 * nilfs_construct_segment - construct a logical segment
 * @sb: super block
 *
 * Return Value: On success, 0 is returned. On errors, one of the following
 * negative error code is returned.
 *
 * %-EROFS - Read only filesystem.
 *
 * %-EIO - I/O error
 *
 * %-ENOSPC - No space left on device (only in a panic state).
 *
 * %-ERESTARTSYS - Interrupted.
 *
 * %-ENOMEM - Insufficient memory available.
 */
int nilfs_construct_segment(struct super_block *sb)
{}

/**
 * nilfs_construct_dsync_segment - construct a data-only logical segment
 * @sb: super block
 * @inode: inode whose data blocks should be written out
 * @start: start byte offset
 * @end: end byte offset (inclusive)
 *
 * Return Value: On success, 0 is returned. On errors, one of the following
 * negative error code is returned.
 *
 * %-EROFS - Read only filesystem.
 *
 * %-EIO - I/O error
 *
 * %-ENOSPC - No space left on device (only in a panic state).
 *
 * %-ERESTARTSYS - Interrupted.
 *
 * %-ENOMEM - Insufficient memory available.
 */
int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
				  loff_t start, loff_t end)
{}

#define FLUSH_FILE_BIT
#define FLUSH_DAT_BIT

/**
 * nilfs_segctor_accept - record accepted sequence count of log-write requests
 * @sci: segment constructor object
 */
static void nilfs_segctor_accept(struct nilfs_sc_info *sci)
{}

/**
 * nilfs_segctor_notify - notify the result of request to caller threads
 * @sci: segment constructor object
 * @mode: mode of log forming
 * @err: error code to be notified
 */
static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err)
{}

/**
 * nilfs_segctor_construct - form logs and write them to disk
 * @sci: segment constructor object
 * @mode: mode of log forming
 */
static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
{}

static void nilfs_construction_timeout(struct timer_list *t)
{}

static void
nilfs_remove_written_gcinodes(struct the_nilfs *nilfs, struct list_head *head)
{}

int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
			 void **kbufs)
{}

static void nilfs_segctor_thread_construct(struct nilfs_sc_info *sci, int mode)
{}

static void nilfs_segctor_do_immediate_flush(struct nilfs_sc_info *sci)
{}

static int nilfs_segctor_flush_mode(struct nilfs_sc_info *sci)
{}

/**
 * nilfs_segctor_thread - main loop of the segment constructor thread.
 * @arg: pointer to a struct nilfs_sc_info.
 *
 * nilfs_segctor_thread() initializes a timer and serves as a daemon
 * to execute segment constructions.
 */
static int nilfs_segctor_thread(void *arg)
{}

static int nilfs_segctor_start_thread(struct nilfs_sc_info *sci)
{}

static void nilfs_segctor_kill_thread(struct nilfs_sc_info *sci)
	__acquires(&sci->sc_state_lock)
	__releases(&sci->sc_state_lock)
{}

/*
 * Setup & clean-up functions
 */
static struct nilfs_sc_info *nilfs_segctor_new(struct super_block *sb,
					       struct nilfs_root *root)
{}

static void nilfs_segctor_write_out(struct nilfs_sc_info *sci)
{}

/**
 * nilfs_segctor_destroy - destroy the segment constructor.
 * @sci: nilfs_sc_info
 *
 * nilfs_segctor_destroy() kills the segctord thread and frees
 * the nilfs_sc_info struct.
 * Caller must hold the segment semaphore.
 */
static void nilfs_segctor_destroy(struct nilfs_sc_info *sci)
{}

/**
 * nilfs_attach_log_writer - attach log writer
 * @sb: super block instance
 * @root: root object of the current filesystem tree
 *
 * This allocates a log writer object, initializes it, and starts the
 * log writer.
 *
 * Return Value: On success, 0 is returned. On error, one of the following
 * negative error code is returned.
 *
 * %-ENOMEM - Insufficient memory available.
 */
int nilfs_attach_log_writer(struct super_block *sb, struct nilfs_root *root)
{}

/**
 * nilfs_detach_log_writer - destroy log writer
 * @sb: super block instance
 *
 * This kills log writer daemon, frees the log writer object, and
 * destroys list of dirty files.
 */
void nilfs_detach_log_writer(struct super_block *sb)
{}