linux/fs/smb/server/vfs_cache.h

191 lines
4.9 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2019 Samsung Electronics Co., Ltd.
*/
#ifndef __VFS_CACHE_H__
#define __VFS_CACHE_H__
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/rwsem.h>
#include <linux/spinlock.h>
#include <linux/idr.h>
#include <linux/workqueue.h>
#include "vfs.h"
#include "mgmt/share_config.h"
/* Windows style file permissions for extended response */
#define FILE_GENERIC_ALL 0x1F01FF
#define FILE_GENERIC_READ 0x120089
#define FILE_GENERIC_WRITE 0x120116
#define FILE_GENERIC_EXECUTE 0X1200a0
#define KSMBD_START_FID 0
#define KSMBD_NO_FID (INT_MAX)
#define SMB2_NO_FID (0xFFFFFFFFFFFFFFFFULL)
struct ksmbd_conn;
struct ksmbd_session;
struct ksmbd_lock {
struct file_lock *fl;
struct list_head clist;
struct list_head flist;
struct list_head llist;
unsigned int flags;
int cmd;
int zero_len;
unsigned long long start;
unsigned long long end;
};
struct stream {
char *name;
ssize_t size;
};
struct ksmbd_inode {
struct rw_semaphore m_lock;
atomic_t m_count;
atomic_t op_count;
/* opinfo count for streams */
atomic_t sop_count;
struct dentry *m_de;
unsigned int m_flags;
struct hlist_node m_hash;
struct list_head m_fp_list;
struct list_head m_op_list;
struct oplock_info *m_opinfo;
__le32 m_fattr;
};
enum {
FP_NEW = 0,
FP_INITED,
FP_CLOSED
};
struct ksmbd_file {
struct file *filp;
u64 persistent_id;
u64 volatile_id;
spinlock_t f_lock;
struct ksmbd_inode *f_ci;
struct ksmbd_inode *f_parent_ci;
struct oplock_info __rcu *f_opinfo;
struct ksmbd_conn *conn;
struct ksmbd_tree_connect *tcon;
atomic_t refcount;
__le32 daccess;
__le32 saccess;
__le32 coption;
__le32 cdoption;
__u64 create_time;
__u64 itime;
bool is_nt_open;
bool attrib_only;
char client_guid[16];
char create_guid[16];
char app_instance_id[16];
struct stream stream;
struct list_head node;
struct list_head blocked_works;
struct list_head lock_list;
int durable_timeout;
int durable_scavenger_timeout;
/* if ls is happening on directory, below is valid*/
struct ksmbd_readdir_data readdir_data;
int dot_dotdot[2];
unsigned int f_state;
bool reserve_lease_break;
bool is_durable;
bool is_persistent;
bool is_resilient;
};
static inline void set_ctx_actor(struct dir_context *ctx,
filldir_t actor)
{
ctx->actor = actor;
}
#define KSMBD_NR_OPEN_DEFAULT BITS_PER_LONG
struct ksmbd_file_table {
rwlock_t lock;
struct idr *idr;
};
static inline bool has_file_id(u64 id)
{
return id < KSMBD_NO_FID;
}
static inline bool ksmbd_stream_fd(struct ksmbd_file *fp)
{
return fp->stream.name != NULL;
}
int ksmbd_init_file_table(struct ksmbd_file_table *ft);
void ksmbd_destroy_file_table(struct ksmbd_file_table *ft);
int ksmbd_close_fd(struct ksmbd_work *work, u64 id);
struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, u64 id);
struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, u64 id);
struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
u64 pid);
void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp);
struct ksmbd_inode *ksmbd_inode_lookup_lock(struct dentry *d);
void ksmbd_inode_put(struct ksmbd_inode *ci);
struct ksmbd_file *ksmbd_lookup_global_fd(unsigned long long id);
struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
void ksmbd_put_durable_fd(struct ksmbd_file *fp);
struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
void ksmbd_launch_ksmbd_durable_scavenger(void);
void ksmbd_stop_durable_scavenger(void);
void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
void ksmbd_close_session_fds(struct ksmbd_work *work);
int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
int ksmbd_init_global_file_table(void);
void ksmbd_free_global_file_table(void);
void ksmbd_set_fd_limit(unsigned long limit);
void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
unsigned int state);
/*
* INODE hash
*/
int __init ksmbd_inode_hash_init(void);
cifsd: fix error handling in ksmbd_server_init() The error handling in ksmbd_server_init() uses "one function to free everything style" which is impossible to audit and leads to several canonical bugs. When we free something that wasn't allocated it may be uninitialized, an error pointer, freed in a different function or we try freeing "foo->bar" when "foo" is a NULL pointer. And since the code is impossible to audit then it leads to memory leaks. In the ksmbd_server_init() function, every goto will lead to a crash because we have not allocated the work queue but we call ksmbd_workqueue_destroy() which tries to flush a NULL work queue. Another bug is if ksmbd_init_buffer_pools() fails then it leads to a double free because we free "work_cache" twice. A third type of bug is that we forgot to call ksmbd_release_inode_hash() so that is a resource leak. A better way to write error handling is for every function to clean up after itself and never leave things partially allocated. Then we can use "free the last successfully allocated resource" style. That way when someone is reading the code they can just track the last resource in their head and verify that the goto matches what they expect. In this patch I modified ksmbd_ipc_init() to clean up after itself and then I converted ksmbd_server_init() to use gotos to clean up. Fixes: cabcebc31de4 ("cifsd: introduce SMB3 kernel server") Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com> Signed-off-by: Steve French <stfrench@microsoft.com>
2021-03-23 21:27:04 +08:00
void ksmbd_release_inode_hash(void);
enum KSMBD_INODE_STATUS {
KSMBD_INODE_STATUS_OK,
KSMBD_INODE_STATUS_UNKNOWN,
KSMBD_INODE_STATUS_PENDING_DELETE,
};
int ksmbd_query_inode_status(struct dentry *dentry);
bool ksmbd_inode_pending_delete(struct ksmbd_file *fp);
void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp);
void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp);
void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp,
int file_info);
int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp);
int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share,
struct ksmbd_file *fp, char *name);
int ksmbd_init_file_cache(void);
void ksmbd_exit_file_cache(void);
#endif /* __VFS_CACHE_H__ */