linux/fs/smb/client/file.c

// SPDX-License-Identifier: LGPL-2.1
/*
 *
 *   vfs operations that deal with files
 *
 *   Copyright (C) International Business Machines  Corp., 2002,2010
 *   Author(s): Steve French ([email protected])
 *              Jeremy Allison ([email protected])
 *
 */
#include <linux/fs.h>
#include <linux/filelock.h>
#include <linux/backing-dev.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
#include <linux/writeback.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/delay.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/mm.h>
#include <asm/div64.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "smb2proto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "fscache.h"
#include "smbdirect.h"
#include "fs_context.h"
#include "cifs_ioctl.h"
#include "cached_dir.h"
#include <trace/events/netfs.h>

static int cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush);

/*
 * Prepare a subrequest to upload to the server.  We need to allocate credits
 * so that we know the maximum amount of data that we can include in it.
 */
static void cifs_prepare_write(struct netfs_io_subrequest *subreq)
{}

/*
 * Issue a subrequest to upload to the server.
 */
static void cifs_issue_write(struct netfs_io_subrequest *subreq)
{}

static void cifs_netfs_invalidate_cache(struct netfs_io_request *wreq)
{}

/*
 * Split the read up according to how many credits we can get for each piece.
 * It's okay to sleep here if we need to wait for more credit to become
 * available.
 *
 * We also choose the server and allocate an operation ID to be cleaned up
 * later.
 */
static bool cifs_clamp_length(struct netfs_io_subrequest *subreq)
{}

/*
 * Issue a read operation on behalf of the netfs helper functions.  We're asked
 * to make a read of a certain size at a point in the file.  We are permitted
 * to only read a portion of that, but as long as we read something, the netfs
 * helper will call us again so that we can issue another read.
 */
static void cifs_req_issue_read(struct netfs_io_subrequest *subreq)
{}

/*
 * Writeback calls this when it finds a folio that needs uploading.  This isn't
 * called if writeback only has copy-to-cache to deal with.
 */
static void cifs_begin_writeback(struct netfs_io_request *wreq)
{}

/*
 * Initialise a request.
 */
static int cifs_init_request(struct netfs_io_request *rreq, struct file *file)
{}

/*
 * Completion of a request operation.
 */
static void cifs_rreq_done(struct netfs_io_request *rreq)
{}

static void cifs_post_modify(struct inode *inode)
{}

static void cifs_free_request(struct netfs_io_request *rreq)
{}

static void cifs_free_subrequest(struct netfs_io_subrequest *subreq)
{}

const struct netfs_request_ops cifs_req_ops =;

/*
 * Mark as invalid, all open files on tree connections since they
 * were closed when session to server was lost.
 */
void
cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
{}

static inline int cifs_convert_flags(unsigned int flags, int rdwr_for_fscache)
{}

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
static u32 cifs_posix_convert_flags(unsigned int flags)
{}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

static inline int cifs_get_disposition(unsigned int flags)
{}

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
int cifs_posix_open(const char *full_path, struct inode **pinode,
			struct super_block *sb, int mode, unsigned int f_flags,
			__u32 *poplock, __u16 *pnetfid, unsigned int xid)
{}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
			struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock,
			struct cifs_fid *fid, unsigned int xid, struct cifs_open_info_data *buf)
{}

static bool
cifs_has_mand_locks(struct cifsInodeInfo *cinode)
{}

void
cifs_down_write(struct rw_semaphore *sem)
{}

static void cifsFileInfo_put_work(struct work_struct *work);
void serverclose_work(struct work_struct *work);

struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
				       struct tcon_link *tlink, __u32 oplock,
				       const char *symlink_target)
{}

struct cifsFileInfo *
cifsFileInfo_get(struct cifsFileInfo *cifs_file)
{}

static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file)
{}

static void cifsFileInfo_put_work(struct work_struct *work)
{}

void serverclose_work(struct work_struct *work)
{}

/**
 * cifsFileInfo_put - release a reference of file priv data
 *
 * Always potentially wait for oplock handler. See _cifsFileInfo_put().
 *
 * @cifs_file:	cifs/smb3 specific info (eg refcounts) for an open file
 */
void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
{}

/**
 * _cifsFileInfo_put - release a reference of file priv data
 *
 * This may involve closing the filehandle @cifs_file out on the
 * server. Must be called without holding tcon->open_file_lock,
 * cinode->open_file_lock and cifs_file->file_info_lock.
 *
 * If @wait_for_oplock_handler is true and we are releasing the last
 * reference, wait for any running oplock break handler of the file
 * and cancel any pending one.
 *
 * @cifs_file:	cifs/smb3 specific info (eg refcounts) for an open file
 * @wait_oplock_handler: must be false if called from oplock_break_handler
 * @offload:	not offloaded on close and oplock breaks
 *
 */
void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
		       bool wait_oplock_handler, bool offload)
{}

int cifs_open(struct inode *inode, struct file *file)

{}

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
static int cifs_push_posix_locks(struct cifsFileInfo *cfile);
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

/*
 * Try to reacquire byte range locks that were released when session
 * to server was lost.
 */
static int
cifs_relock_file(struct cifsFileInfo *cfile)
{}

static int
cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
{}

void smb2_deferred_work_close(struct work_struct *work)
{}

static bool
smb2_can_defer_close(struct inode *inode, struct cifs_deferred_close *dclose)
{}

int cifs_close(struct inode *inode, struct file *file)
{}

void
cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
{}

int cifs_closedir(struct inode *inode, struct file *file)
{}

static struct cifsLockInfo *
cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 flags)
{}

void
cifs_del_lock_waiters(struct cifsLockInfo *lock)
{}

#define CIFS_LOCK_OP
#define CIFS_READ_OP
#define CIFS_WRITE_OP

/* @rw_check : 0 - no op, 1 - read, 2 - write */
static bool
cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
			    __u64 length, __u8 type, __u16 flags,
			    struct cifsFileInfo *cfile,
			    struct cifsLockInfo **conf_lock, int rw_check)
{}

bool
cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
			__u8 type, __u16 flags,
			struct cifsLockInfo **conf_lock, int rw_check)
{}

/*
 * Check if there is another lock that prevents us to set the lock (mandatory
 * style). If such a lock exists, update the flock structure with its
 * properties. Otherwise, set the flock type to F_UNLCK if we can cache brlocks
 * or leave it the same if we can't. Returns 0 if we don't need to request to
 * the server or 1 otherwise.
 */
static int
cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
	       __u8 type, struct file_lock *flock)
{}

static void
cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
{}

/*
 * Set the byte-range lock (mandatory style). Returns:
 * 1) 0, if we set the lock and don't need to request to the server;
 * 2) 1, if no locks prevent us but we need to request to the server;
 * 3) -EACCES, if there is a lock that prevents us and wait is false.
 */
static int
cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock,
		 bool wait)
{}

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
/*
 * Check if there is another lock that prevents us to set the lock (posix
 * style). If such a lock exists, update the flock structure with its
 * properties. Otherwise, set the flock type to F_UNLCK if we can cache brlocks
 * or leave it the same if we can't. Returns 0 if we don't need to request to
 * the server or 1 otherwise.
 */
static int
cifs_posix_lock_test(struct file *file, struct file_lock *flock)
{}

/*
 * Set the byte-range lock (posix style). Returns:
 * 1) <0, if the error occurs while setting the lock;
 * 2) 0, if we set the lock and don't need to request to the server;
 * 3) FILE_LOCK_DEFERRED, if we will wait for some other file_lock;
 * 4) FILE_LOCK_DEFERRED + 1, if we need to request to the server.
 */
static int
cifs_posix_lock_set(struct file *file, struct file_lock *flock)
{}

int
cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
{}

static __u32
hash_lockowner(fl_owner_t owner)
{}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

struct lock_to_push {};

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
static int
cifs_push_posix_locks(struct cifsFileInfo *cfile)
{}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

static int
cifs_push_locks(struct cifsFileInfo *cfile)
{}

static void
cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock,
		bool *wait_flag, struct TCP_Server_Info *server)
{}

static int
cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
	   bool wait_flag, bool posix_lck, unsigned int xid)
{}

void
cifs_move_llist(struct list_head *source, struct list_head *dest)
{}

void
cifs_free_llist(struct list_head *llist)
{}

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
int
cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
		  unsigned int xid)
{}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

static int
cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
	   bool wait_flag, bool posix_lck, int lock, int unlock,
	   unsigned int xid)
{}

int cifs_flock(struct file *file, int cmd, struct file_lock *fl)
{}

int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
{}

void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result,
				      bool was_async)
{}

struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
					bool fsuid_only)
{}

/* Return -EBADF if no handle is found and general rc otherwise */
int
cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags,
		       struct cifsFileInfo **ret_file)
{}

struct cifsFileInfo *
find_writable_file(struct cifsInodeInfo *cifs_inode, int flags)
{}

int
cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
		       int flags,
		       struct cifsFileInfo **ret_file)
{}

int
cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
		       struct cifsFileInfo **ret_file)
{}

/*
 * Flush data on a strict file.
 */
int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
		      int datasync)
{}

/*
 * Flush data on a non-strict data.
 */
int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{}

/*
 * As file closes, flush all cached write data for this inode checking
 * for write behind errors.
 */
int cifs_flush(struct file *file, fl_owner_t id)
{}

static ssize_t
cifs_writev(struct kiocb *iocb, struct iov_iter *from)
{}

ssize_t
cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from)
{}

ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter)
{}

ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{}

ssize_t
cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
{}

static vm_fault_t cifs_page_mkwrite(struct vm_fault *vmf)
{}

static const struct vm_operations_struct cifs_file_vm_ops =;

int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
{}

int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
{}

static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
{}

/* We do not want to update the file size from server for inodes
   open for write - to avoid races with writepage extending
   the file - in the future we could consider allowing
   refreshing the inode only on increases in the file size
   but this is tricky to do without racing with writebehind
   page caching in the current Linux kernel design */
bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file,
			    bool from_readdir)
{}

void cifs_oplock_break(struct work_struct *work)
{}

static int cifs_swap_activate(struct swap_info_struct *sis,
			      struct file *swap_file, sector_t *span)
{}

static void cifs_swap_deactivate(struct file *file)
{}

/**
 * cifs_swap_rw - SMB3 address space operation for swap I/O
 * @iocb: target I/O control block
 * @iter: I/O buffer
 *
 * Perform IO to the swap-file.  This is much like direct IO.
 */
static int cifs_swap_rw(struct kiocb *iocb, struct iov_iter *iter)
{}

const struct address_space_operations cifs_addr_ops =;

/*
 * cifs_readahead requires the server to support a buffer large enough to
 * contain the header plus one complete page of data.  Otherwise, we need
 * to leave cifs_readahead out of the address space operations.
 */
const struct address_space_operations cifs_addr_ops_smallbuf =;