/* * Allocate and initialise a request structure */ static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server, int bufsize) { struct smb_request *req; unsigned char *buf = NULL; req = kmem_cache_alloc(req_cachep, SLAB_KERNEL); VERBOSE("allocating request: %p\n", req); if (!req) goto out; if (bufsize > 0) { buf = smb_kmalloc(bufsize, GFP_NOFS); if (!buf) { kmem_cache_free(req_cachep, req); return NULL; } } memset(req, 0, sizeof(struct smb_request)); req->rq_buffer = buf; req->rq_bufsize = bufsize; req->rq_server = server; init_waitqueue_head(&req->rq_wait); INIT_LIST_HEAD(&req->rq_queue); atomic_set(&req->rq_count, 1); out: return req; }
static int smb_create(struct inode *dir, const char *name, int len, int mode, struct inode **result) { int error; struct smb_dirent entry; struct smb_inode_info *new_inode_info; *result = NULL; if (!dir || !S_ISDIR(dir->i_mode)) { printk("smb_create: inode is NULL or not a directory\n"); iput(dir); return -ENOENT; } new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info), GFP_KERNEL); if (new_inode_info == NULL) { iput(dir); return -ENOMEM; } error = smb_proc_create(dir, name, len, 0, CURRENT_TIME); if (error < 0) { smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info)); iput(dir); return error; } smb_invalid_dir_cache(dir->i_ino); if ((error = smb_proc_getattr(dir, name, len, &entry)) < 0) { smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info)); iput(dir); return error; } entry.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1); new_inode_info->finfo = entry; if ((*result = smb_iget(dir, new_inode_info)) == NULL) { iput(dir); return error; } iput(dir); return 0; }
static int smb_lookup(struct inode *dir, const char *name, int len, struct inode **result) { struct smb_dirent finfo; struct smb_inode_info *result_info; int error; int found_in_cache; struct smb_inode_info *new_inode_info = NULL; *result = NULL; if (!dir || !S_ISDIR(dir->i_mode)) { printk("smb_lookup: inode is NULL or not a directory.\n"); iput(dir); return -ENOENT; } DDPRINTK("smb_lookup: %s\n", name); /* Fast cheat for . */ if (len == 0 || (len == 1 && name[0] == '.')) { *result = dir; return 0; } /* ..and for .. */ if (len == 2 && name[0] == '.' && name[1] == '.') { struct smb_inode_info *parent = SMB_INOP(dir)->dir; if (parent->state == SMB_INODE_CACHED) { parent->state = SMB_INODE_LOOKED_UP; } *result = iget(dir->i_sb, smb_info_ino(parent)); iput(dir); if (*result == 0) { return -EACCES; } return 0; } result_info = smb_find_dir_inode(dir, name, len); in_tree: if (result_info != NULL) { if (result_info->state == SMB_INODE_CACHED) { result_info->state = SMB_INODE_LOOKED_UP; } *result = iget(dir->i_sb, smb_info_ino(result_info)); iput(dir); if (new_inode_info != NULL) { smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info)); } if (*result == NULL) { return -EACCES; } return 0; } /* If the file is in the dir cache, we do not have to ask the server. */ found_in_cache = 0; if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino) && (c_size != 0)) { int first = c_last_returned_index; int i; i = first; do { if (compare_filename(SMB_SERVER(dir), name, len, &(c_entry[i])) == 0) { finfo = c_entry[i]; found_in_cache = 1; break; } i = (i + 1) % c_size; } while (i != first); } if (found_in_cache == 0) { DPRINTK("smb_lookup: not found in cache: %s\n", name); if (len > SMB_MAXNAMELEN) { iput(dir); return -ENAMETOOLONG; } error = smb_proc_getattr(dir, name, len, &finfo); if (error < 0) { iput(dir); return error; } finfo.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1); } new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info), GFP_KERNEL); /* Here somebody else might have inserted the inode */ result_info = smb_find_dir_inode(dir, name, len); if (result_info != NULL) { goto in_tree; } if (new_inode_info == NULL) { iput(dir); return -ENOMEM; } new_inode_info->finfo = finfo; DPRINTK("attr: %x\n", finfo.attr); if ((*result = smb_iget(dir, new_inode_info)) == NULL) { iput(dir); return -EACCES; } DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long) result_info); iput(dir); return 0; }
/* Hmm, should we do this like the NFS mount command does? Guess so.. */ struct super_block * smb_read_super(struct super_block *sb, void *raw_data, int silent) { struct smb_mount_data *data = (struct smb_mount_data *) raw_data; struct smb_server *server; struct smb_sb_info *smb_sb; unsigned int fd; struct file *filp; kdev_t dev = sb->s_dev; int error; if (!data) { printk("smb_read_super: missing data argument\n"); sb->s_dev = 0; return NULL; } fd = data->fd; if (data->version != SMB_MOUNT_VERSION) { printk("smb warning: mount version %s than kernel\n", (data->version < SMB_MOUNT_VERSION) ? "older" : "newer"); } if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) { printk("smb_read_super: invalid file descriptor\n"); sb->s_dev = 0; return NULL; } if (!S_ISSOCK(filp->f_inode->i_mode)) { printk("smb_read_super: not a socket!\n"); sb->s_dev = 0; return NULL; } /* We must malloc our own super-block info */ smb_sb = (struct smb_sb_info *)smb_kmalloc(sizeof(struct smb_sb_info), GFP_KERNEL); if (smb_sb == NULL) { printk("smb_read_super: could not alloc smb_sb_info\n"); return NULL; } filp->f_count += 1; lock_super(sb); SMB_SBP(sb) = smb_sb; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; sb->s_magic = SMB_SUPER_MAGIC; sb->s_dev = dev; sb->s_op = &smb_sops; server = &(SMB_SBP(sb)->s_server); server->sock_file = filp; server->lock = 0; server->wait = NULL; server->packet = NULL; server->max_xmit = data->max_xmit; if (server->max_xmit <= 0) server->max_xmit = SMB_DEF_MAX_XMIT; server->tid = 0; server->pid = current->pid; server->mid = current->pid + 20; server->m = *data; server->m.file_mode = (server->m.file_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG; server->m.dir_mode = (server->m.dir_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR; smb_init_root(server); /* * Make the connection to the server */ error = smb_proc_connect(server); unlock_super(sb); if (error < 0) { sb->s_dev = 0; printk("smb_read_super: Failed connection, bailing out " "(error = %d).\n", -error); goto fail; } if (server->protocol >= PROTOCOL_LANMAN2) server->case_handling = CASE_DEFAULT; else server->case_handling = CASE_LOWER; if ((error = smb_proc_dskattr(sb, &(SMB_SBP(sb)->s_attr))) < 0) { sb->s_dev = 0; printk("smb_read_super: could not get super block " "attributes\n"); smb_kfree_s(server->packet, server->max_xmit); goto fail; } if ((error = smb_stat_root(server)) < 0) { sb->s_dev = 0; printk("smb_read_super: could not get root dir attributes\n"); smb_kfree_s(server->packet, server->max_xmit); goto fail; } DPRINTK("smb_read_super : %u %u %u %u\n", SMB_SBP(sb)->s_attr.total, SMB_SBP(sb)->s_attr.blocksize, SMB_SBP(sb)->s_attr.allocblocks, SMB_SBP(sb)->s_attr.free); DPRINTK("smb_read_super: SMB_SBP(sb) = %x\n", (int)SMB_SBP(sb)); if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) { sb->s_dev = 0; printk("smb_read_super: get root inode failed\n"); smb_kfree_s(server->packet, server->max_xmit); goto fail; } MOD_INC_USE_COUNT; return sb; fail: filp->f_count -= 1; smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info)); return NULL; }
static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) { struct smb_sb_info *server; struct smb_mount_data_kernel *mnt; struct smb_mount_data *oldmnt; struct inode *root_inode; struct smb_fattr root; int ver; void *mem; if (!raw_data) goto out_no_data; oldmnt = (struct smb_mount_data *) raw_data; ver = oldmnt->version; if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII) goto out_wrong_data; sb->s_flags |= MS_NODIRATIME; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; sb->s_magic = SMB_SUPER_MAGIC; sb->s_op = &smb_sops; sb->s_time_gran = 100; server = smb_kmalloc(sizeof(struct smb_sb_info), GFP_KERNEL); if (!server) goto out_no_server; sb->s_fs_info = server; memset(server, 0, sizeof(struct smb_sb_info)); server->super_block = sb; server->mnt = NULL; server->sock_file = NULL; init_waitqueue_head(&server->conn_wq); init_MUTEX(&server->sem); INIT_LIST_HEAD(&server->entry); INIT_LIST_HEAD(&server->xmitq); INIT_LIST_HEAD(&server->recvq); server->conn_error = 0; server->conn_pid = 0; server->state = CONN_INVALID; /* no connection yet */ server->generation = 0; /* Allocate the global temp buffer and some superblock helper structs */ /* FIXME: move these to the smb_sb_info struct */ VERBOSE("alloc chunk = %d\n", sizeof(struct smb_ops) + sizeof(struct smb_mount_data_kernel)); mem = smb_kmalloc(sizeof(struct smb_ops) + sizeof(struct smb_mount_data_kernel), GFP_KERNEL); if (!mem) goto out_no_mem; server->ops = mem; smb_install_null_ops(server->ops); server->mnt = mem + sizeof(struct smb_ops); /* Setup NLS stuff */ server->remote_nls = NULL; server->local_nls = NULL; mnt = server->mnt; memset(mnt, 0, sizeof(struct smb_mount_data_kernel)); strlcpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, SMB_NLS_MAXNAMELEN); strlcpy(mnt->codepage.remote_name, SMB_NLS_REMOTE, SMB_NLS_MAXNAMELEN); mnt->ttl = SMB_TTL_DEFAULT; if (ver == SMB_MOUNT_OLDVERSION) { mnt->version = oldmnt->version; SET_UID(mnt->uid, oldmnt->uid); SET_GID(mnt->gid, oldmnt->gid); mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG; mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR; mnt->flags = (oldmnt->file_mode >> 9) | SMB_MOUNT_UID | SMB_MOUNT_GID | SMB_MOUNT_FMODE | SMB_MOUNT_DMODE; } else {