/*
 * nasd_edrfs_client_linux.h
 *
 * Types for EDRFS in the Linux kernel.
 *
 * Author: Nat Lanza
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#ifndef _NASD_EDRFS_LINUX_CLIENT_H
#define _NASD_EDRFS_LINUX_CLIENT_H

#include <nasd/nasd_options.h>
#include <nasd/nasd_sys.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_freelist.h>
#include <nasd/nasd_edrfs_client.h>
#include <nasd/nasd_pdrive_client.h> /* for nasd_drive_handle_t */
#include <nasd/nasd_edrfs_types.h>
#include <nasd/nasd_edrfs_dir.h>

#include <linux/fs.h>
#include <linux/dcache.h>

#include <linux/iobuf.h>

#define NASD_EDRFS_SUPER_MAGIC      0x46554b54
#define NASD_EDRFS_MAX_ACTIVE_CAPS  1024
#define NASD_EDRFS_CAP_TABLE_SZ     128

#define NASD_EDRFS_BUFFER_USER 1
#define NASD_EDRFS_BUFFER_KERNEL 0

#define NASD_EDRFS_IO_DEFAULT_CACHE_THRESHOLD 32

#define NASD_EDRFS_INODE_INFO(_inodep_) \
        ((nasd_edrfs_inode_info_t *) (_inodep_->u.generic_ip))
#define NASD_EDRFS_SUPER_SBINFO(_superp_) \
        ((nasd_edrfs_sb_info_t *) (_superp_->u.generic_sbp))
#define NASD_EDRFS_INODE_IDENT(_inodep_) \
        ((NASD_EDRFS_INODE_INFO(_inodep_))->ident);

#define NASD_EDRFS_MAX_ATTR_TIMEOUT(_inodep_) (S_ISDIR(inode->i_mode) \
        ? NASD_EDRFS_SUPER_SBINFO(_inodep_->i_sb)->max_dir_attrcache \
        : NASD_EDRFS_SUPER_SBINFO(_inodep_->i_sb)->max_file_attrcache)

#define NASD_EDRFS_MIN_ATTR_TIMEOUT(_inodep_) (S_ISDIR(inode->i_mode) \
        ? NASD_EDRFS_SUPER_SBINFO(_inodep_->i_sb)->min_dir_attrcache \
        : NASD_EDRFS_SUPER_SBINFO(_inodep_->i_sb)->min_file_attrcache)

#define NASD_BINDING_SERVER_VALID 1
#define NASD_BINDING_DRIVE_VALID  2
#define NASD_BINDING_DRIVE_NEW    4

typedef struct nasd_edrfs_handles_s {
  nasd_edrfs_handle_t    server_handle;
  nasd_drive_handle_t    drive_handle;
  nasd_int32             drive_address;
  nasd_int32             flags;
  nasd_int32             partnum;
  nasd_disk_ident_t      disk_identifier;
} nasd_edrfs_handles_t;

typedef struct nasd_edrfs_inode_attr_cache_info_s {
  int            cache_valid;
  unsigned long  cached_since;
  unsigned long  cached_mtime;
  unsigned long  cache_timeout;
} nasd_edrfs_inode_attr_cache_info_t;

/* private info for each inode */
typedef struct nasd_edrfs_inode_info_s {
  nasd_edrfs_identifier_t              ident;
  nasd_edrfs_inode_attr_cache_info_t   cache_info;
} nasd_edrfs_inode_info_t;


/* private info at the superblock */
typedef struct nasd_edrfs_sb_info_s {
  nasd_edrfs_handles_t  handles;
  unsigned long         min_dir_attrcache;
  unsigned long         max_dir_attrcache;
  unsigned long         min_file_attrcache;
  unsigned long         max_file_attrcache;
  unsigned long         max_file_read_cache_size;
  unsigned long         max_dir_read_cache_size;
  int                   readonly;
  int                   server_parse; /* do client-side parsing? */
} nasd_edrfs_sb_info_t;


/* entry in the capability cache */
typedef struct nasd_edrfs_captable_entry_s nasd_edrfs_captable_entry_t;
struct nasd_edrfs_captable_entry_s {
  nasd_edrfs_identifier_t       identifier; /*  16 bytes */ 
  nasd_edrfs_credential_t       cred;       /*   8 bytes */
  nasd_cookie_t                 cookie;     /*  56 bytes */
  nasd_edrfs_captable_entry_t  *next;       /*   8 bytes */
  nasd_edrfs_captable_entry_t  *prev;       /*   8 bytes */
  nasd_edrfs_captable_entry_t  *l_next;     /*   8 bytes */
  nasd_edrfs_captable_entry_t  *l_prev;     /*   8 bytes */
};                                          /* 112 bytes total */


#define SETUP_SECURITY_PARAM(_sp_, _cap_) { \
    (_sp_).type=(_cap_).type; \
    (_sp_).partnum=(_cap_).partnum; \
    (_sp_).actual_protection=(_cap_).min_protection; \
}


static inline unsigned long
nasd_edrfs_nasd_ident_to_ino(nasd_identifier_t nasd_id) {
  /* very secretly the low 32 bits of a NASD identifier are unique.
     how ever, that might change and we're bad people for assuming it.
     so we all go to hell, but at least we have unique inode numbers. */
  return (unsigned long) ((unsigned long long) nasd_id &
			  (unsigned long long) 0x00000000ffffffffULL );
}


static inline unsigned long
nasd_edrfs_ident_to_ino(nasd_edrfs_identifier_t *ident) {
  return nasd_edrfs_nasd_ident_to_ino(ident->nasd_identifier);
}


/*
 * Freelists
 */

typedef struct nasd_edrfs_super_data_s     nasd_edrfs_super_data_t;
typedef struct nasd_edrfs_readdir_data_s   nasd_edrfs_readdir_data_t;
typedef struct nasd_edrfs_create_data_s    nasd_edrfs_create_data_t;
typedef struct nasd_edrfs_rename_data_s    nasd_edrfs_rename_data_t;
typedef struct nasd_edrfs_lookup_data_s    nasd_edrfs_lookup_data_t;
typedef struct nasd_edrfs_mkdir_data_s     nasd_edrfs_mkdir_data_t;
typedef struct nasd_edrfs_notify_data_s    nasd_edrfs_notify_data_t;
typedef struct nasd_edrfs_kiobuf_data_s    nasd_edrfs_kiobuf_data_t;

struct nasd_edrfs_super_data_s {
  nasd_edrfs_mount_args_t           args;
  nasd_edrfs_mount_res_t            res;
  nasd_attribute_t                  attr;
  nasd_edrfs_attributes_t           edrfsattr;
  struct nasd_edrfs_super_data_s *next;
};


#define NASD_EDRFS_READDIR_ENT_MAX ((8192 - sizeof(nasd_edrfs_readdir_args_t) \
                                     - sizeof(nasd_edrfs_readdir_res_t)) \
                                    / sizeof(nasd_edrfs_dirent_t))

struct nasd_edrfs_readdir_data_s {
  nasd_edrfs_readdir_args_t          args;
  nasd_edrfs_readdir_res_t           res;
  nasd_edrfs_dirent_t               out_entries[NASD_EDRFS_READDIR_ENT_MAX];
  struct nasd_edrfs_readdir_data_s  *next;
};

struct nasd_edrfs_create_data_s {
  nasd_edrfs_create_args_t          args;
  nasd_edrfs_create_res_t           res;
  nasd_edrfs_attributes_t           edrfsattr;
  struct nasd_edrfs_create_data_s  *next;
};

struct nasd_edrfs_rename_data_s {
  nasd_edrfs_rename_args_t          args;
  nasd_edrfs_rename_res_t           res;
  struct nasd_edrfs_rename_data_s  *next;
};

struct nasd_edrfs_lookup_data_s {
  nasd_edrfs_lookup_args_t          args;
  nasd_edrfs_lookup_res_t           res;
  nasd_attribute_t                  nasdattr;
  nasd_edrfs_attributes_t           edrfsattr;
  nasd_edrfs_identifier_t           edrfsid;
  struct nasd_edrfs_lookup_data_s  *next;
};

struct nasd_edrfs_mkdir_data_s {
  nasd_edrfs_mkdir_args_t           args;
  nasd_edrfs_mkdir_res_t            res;
  nasd_edrfs_attributes_t           edrfsattr;
  struct nasd_edrfs_mkdir_data_s   *next;
};

struct nasd_edrfs_notify_data_s {
  nasd_edrfs_setattr_args_t         args;
  nasd_edrfs_setattr_res_t          res;
  nasd_edrfs_attributes_t           edrfsattr;
  struct nasd_edrfs_notify_data_s   *next;
};

#define NASD_EDRFS_MAX_EMBEDDED_MEMLIST 17
struct nasd_edrfs_kiobuf_data_s {
  struct kiobuf             *iobuf;
  nasd_mem_list_t            memlist[NASD_EDRFS_MAX_EMBEDDED_MEMLIST];
  nasd_mem_list_t           *memlist_alloc;
  int                        num_alloc;
  nasd_edrfs_kiobuf_data_t  *next;
};

/*
 * from nasd_core.c
 */
nasd_edrfs_super_data_t *nasd_edrfs_get_super_data(void);
void nasd_edrfs_free_super_data(nasd_edrfs_super_data_t *cp);
nasd_edrfs_readdir_data_t *nasd_edrfs_get_readdir_data(void);
void nasd_edrfs_free_readdir_data(nasd_edrfs_readdir_data_t *cp);
nasd_edrfs_create_data_t *nasd_edrfs_get_create_data(void);
void nasd_edrfs_free_create_data(nasd_edrfs_create_data_t *cp);
nasd_edrfs_rename_data_t *nasd_edrfs_get_rename_data(void);
void nasd_edrfs_free_rename_data(nasd_edrfs_rename_data_t *cp);
nasd_edrfs_lookup_data_t *nasd_edrfs_get_lookup_data(void);
void nasd_edrfs_free_lookup_data(nasd_edrfs_lookup_data_t *cp);
nasd_edrfs_mkdir_data_t *nasd_edrfs_get_mkdir_data(void);
void nasd_edrfs_free_mkdir_data(nasd_edrfs_mkdir_data_t *cp);
nasd_edrfs_notify_data_t *nasd_edrfs_get_notify_data(void);
void nasd_edrfs_free_notify_data(nasd_edrfs_notify_data_t *cp);
nasd_edrfs_kiobuf_data_t *nasd_edrfs_get_kiobuf_data(void);
void nasd_edrfs_free_kiobuf_data(nasd_edrfs_kiobuf_data_t *cp);
nasd_status_t nasd_edrfs_data_init(void);
void nasd_edrfs_data_shutdown(void);


/*
 * General client functions
 */

int init_nasd_edrfs_fs(void);
int shutdown_nasd_edrfs_fs(void);

nasd_status_t nasd_edrfs_client_fs_init(void);
nasd_status_t nasd_edrfs_client_fs_shutdown(void);

nasd_status_t nasd_edrfs_caps_init(void);

void nasd_edrfs_caps_shutdown(void);

nasd_status_t nasd_edrfs_caps_lookup(nasd_edrfs_identifier_t  *ident,
				     nasd_edrfs_credential_t  *cred,
				     nasd_cookie_t            *cookie);

nasd_status_t nasd_edrfs_caps_insert(nasd_edrfs_identifier_t  *ident,
				     nasd_edrfs_credential_t  *cred,
				     nasd_cookie_t            *cookie);

nasd_status_t nasd_edrfs_find_or_get_cookie(nasd_edrfs_handles_t     *handles,
					    nasd_edrfs_identifier_t  *ident,
					    nasd_edrfs_credential_t  *cred,
					    nasd_cookie_t            *cookie);

nasd_status_t nasd_edrfs_do_getattr(struct super_block       *sb,
				    nasd_edrfs_identifier_t  *ident,
				    nasd_attribute_t         *attr);

int nasd_edrfs_lookup_revalidate(struct dentry  *dentry, int flags);

int nasd_edrfs_revalidate(struct dentry *dentry);

struct inode *nasd_edrfs_ident_get(struct super_block       *sb,
				   nasd_edrfs_identifier_t  *ident,
				   nasd_attribute_t         *nasd_attr,
				   nasd_edrfs_attributes_t  *edrfsattr);

int nasd_edrfs_refresh_inode(struct inode            *inode,
			     nasd_attribute_t        *nasd_attr,
			     nasd_edrfs_attributes_t *edrfs);

nasd_status_t nasd_edrfs_instantiate(struct dentry            *dentry,
				     nasd_edrfs_identifier_t  *identifier,
				     nasd_edrfs_credential_t  *cred,
				     nasd_cookie_t            *cookie,
				     nasd_attribute_t         *nasd_attr,
				     nasd_edrfs_attributes_t  *edrfsattr);

int nasd_edrfs_convert_error(nasd_status_t       rc,
			     nasd_rpc_status_t   op_status);

void nasd_edrfs_invalidate_dircache(struct inode *inode);

nasd_status_t nasd_edrfs_iobuf_to_memlist(nasd_edrfs_kiobuf_data_t *iostuff);

nasd_status_t nasd_edrfs_read_basic(struct inode  *inode,
				    void          *buf,
				    int            buffer_space,
				    nasd_len_t     in_len,
				    nasd_offset_t  offset,
				    nasd_len_t      *out_len);

nasd_status_t nasd_edrfs_write_basic(struct inode   *inode,
				     void           *buf,
				     int             buffer_space,
				     nasd_len_t      in_len,
				     nasd_offset_t   offset,
				     nasd_len_t     *out_len);

nasd_status_t nasd_edrfs_read_memlist(struct inode     *inode,
				      nasd_mem_list_t  *memlist,
				      nasd_len_t        in_len,
				      nasd_offset_t     offset,
				      nasd_len_t       *out_len);

nasd_status_t nasd_edrfs_read_memlist(struct inode     *inode,
				      nasd_mem_list_t  *memlist,
				      nasd_len_t        in_len,
				      nasd_offset_t     offset,
				      nasd_len_t       *out_len);

nasd_status_t nasd_edrfs_read_kiovec(struct inode   *inode,
				     void           *buf,
				     nasd_len_t      in_len,
				     nasd_offset_t   offset,
				     nasd_len_t     *out_len);

nasd_status_t nasd_edrfs_write_kiovec(struct inode   *inode,
				      void           *buf,
				      nasd_len_t      in_len,
				      nasd_offset_t   offset,
				      nasd_len_t     *out_len);


/* nasd_ioctl.c */
int nasd_edrfs_ioctl(struct inode  *inode,
		     struct file   *filp,
		     unsigned int   command,
		     unsigned long  arg);

#endif /* _NASD_EDRFS_LINUX_CLIENT_H */
