Esempio n. 1
0
/*
 * This is the callback when the dcache has a lookup hit.
 */
static int
smb_lookup_validate(struct dentry * dentry, int flags)
{
	struct inode * inode = dentry->d_inode;
	unsigned long age = jiffies - dentry->d_time;
	int valid;

	/*
	 * The default validation is based on dentry age:
	 * we believe in dentries for 5 seconds.  (But each
	 * successful server lookup renews the timestamp.)
	 */
	valid = (age <= SMBFS_MAX_AGE);
#ifdef SMBFS_DEBUG_VERBOSE
	if (!valid)
		VERBOSE("%s/%s not valid, age=%lu\n", DENTRY_PATH(dentry), age);
#endif

	if (inode) {
		if (is_bad_inode(inode)) {
			PARANOIA("%s/%s has dud inode\n", DENTRY_PATH(dentry));
			valid = 0;
		} else if (!valid)
			valid = (smb_revalidate_inode(dentry) == 0);
	} else {
		/*
		 * What should we do for negative dentries?
		 */
	}
	return valid;
}
Esempio n. 2
0
/* 
 * Write to a file (through the page cache).
 */
static ssize_t
smb_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
			       unsigned long nr_segs, loff_t pos)
{
	struct file * file = iocb->ki_filp;
	struct dentry * dentry = file->f_path.dentry;
	ssize_t	result;

	VERBOSE("file %s/%s, count=%lu@%lu\n",
		DENTRY_PATH(dentry),
		(unsigned long) iocb->ki_left, (unsigned long) pos);

	result = smb_revalidate_inode(dentry);
	if (result) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), result);
		goto out;
	}

	result = smb_open(dentry, SMB_O_WRONLY);
	if (result)
		goto out;

	if (iocb->ki_left > 0) {
		result = generic_file_aio_write(iocb, iov, nr_segs, pos);
		VERBOSE("pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
			(long) file->f_pos, (long) dentry->d_inode->i_size,
			dentry->d_inode->i_mtime, dentry->d_inode->i_atime);
	}
out:
	return result;
}
Esempio n. 3
0
static ssize_t
smb_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
			unsigned long nr_segs, loff_t pos)
{
	struct file * file = iocb->ki_filp;
	struct dentry * dentry = file->f_path.dentry;
	ssize_t	status;

	VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
		(unsigned long) iocb->ki_left, (unsigned long) pos);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}

	VERBOSE("before read, size=%ld, flags=%x, atime=%ld\n",
		(long)dentry->d_inode->i_size,
		dentry->d_inode->i_flags, dentry->d_inode->i_atime);

	status = generic_file_aio_read(iocb, iov, nr_segs, pos);
out:
	return status;
}
Esempio n. 4
0
/*
 * Write a page synchronously.
 * Offset is the data offset within the page.
 */
static int
smb_writepage_sync(struct inode *inode, struct page *page,
		   unsigned long pageoffset, unsigned int count)
{
	loff_t offset;
	char *buffer = kmap(page) + pageoffset;
	struct smb_sb_info *server = server_from_inode(inode);
	unsigned int wsize = smb_get_wsize(server);
	int result, written = 0;

	offset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageoffset;
	VERBOSE("file ino=%ld, fileid=%d, count=%d@%Ld, wsize=%d\n",
		inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);

	do {
		if (count < wsize)
			wsize = count;

		result = server->ops->write(inode, offset, wsize, buffer);
		if (result < 0) {
			PARANOIA("failed write, wsize=%d, result=%d\n",
				 wsize, result);
			break;
		}
		/* N.B. what if result < wsize?? */
#ifdef SMBFS_PARANOIA
		if (result < wsize)
			PARANOIA("short write, wsize=%d, result=%d\n",
				 wsize, result);
#endif
		buffer += wsize;
		offset += wsize;
		written += wsize;
		count -= wsize;
		/*
		 * Update the inode now rather than waiting for a refresh.
		 */
		inode->i_mtime = inode->i_atime = CURRENT_TIME;
		inode->u.smbfs_i.flags |= SMB_F_LOCALWRITE;
		if (offset > inode->i_size)
			inode->i_size = offset;
	} while (count);

	kunmap(page);
	return written ? written : result;
}
Esempio n. 5
0
/*
 * This routine is called when i_nlink == 0 and i_count goes to 0.
 * All blocking cleanup operations need to go here to avoid races.
 */
static void
smb_delete_inode(struct inode *ino)
{
	DEBUG1("ino=%ld\n", ino->i_ino);
	lock_kernel();
	if (smb_close(ino))
		PARANOIA("could not close inode %ld\n", ino->i_ino);
	unlock_kernel();
	clear_inode(ino);
}
Esempio n. 6
0
/*
 * This routine is called when i_nlink == 0 and i_count goes to 0.
 * All blocking cleanup operations need to go here to avoid races.
 */
static void
smb_evict_inode(struct inode *ino)
{
	DEBUG1("ino=%ld\n", ino->i_ino);
	truncate_inode_pages(&ino->i_data, 0);
	end_writeback(ino);
	lock_kernel();
	if (smb_close(ino))
		PARANOIA("could not close inode %ld\n", ino->i_ino);
	unlock_kernel();
}
Esempio n. 7
0
int
smb_refill_dircache(struct cache_head * cachep, struct dentry *dentry)
{
	struct inode * inode = dentry->d_inode;
	int result;

	VERBOSE("cache %s/%s, blocks=%d\n", DENTRY_PATH(dentry), cachep->pages);
	/*
	 * Fill the cache, starting at position 2.
	 */
retry:
	inode->u.smbfs_i.cache_valid |= SMB_F_CACHEVALID;
	result = smb_proc_readdir(dentry, 2, cachep);
	if (result < 0)
	{
		PARANOIA("readdir failed, result=%d\n", result);
		goto out;
	}

	/*
	 * Check whether the cache was invalidated while
	 * we were doing the scan ...
	 */
	if (!(inode->u.smbfs_i.cache_valid & SMB_F_CACHEVALID))
	{
		PARANOIA("cache invalidated, retrying\n");
		goto retry;
	}

	result = cachep->status;
	if (!result)
	{
		cachep->valid = 1;
		cachep->mtime = dentry->d_inode->i_mtime;
	}
	VERBOSE("cache %s/%s status=%d, entries=%d\n",
		DENTRY_PATH(dentry), cachep->status, cachep->entries);

out:
	return result;
}
Esempio n. 8
0
static int
smb_get_length(struct socket *socket, unsigned char *header)
{
	int result;
	unsigned char peek_buf[4];
	mm_segment_t fs;

      re_recv:
	fs = get_fs();
	set_fs(get_ds());
	result = smb_receive_raw(socket, peek_buf, 4);
	set_fs(fs);

	if (result < 0)
	{
		PARANOIA("recv error = %d\n", -result);
		return result;
	}
	switch (peek_buf[0])
	{
	case 0x00:
	case 0x82:
		break;

	case 0x85:
		DEBUG1("Got SESSION KEEP ALIVE\n");
		goto re_recv;

	default:
		PARANOIA("Invalid NBT packet, code=%x\n", peek_buf[0]);
		return -EIO;
	}

	if (header != NULL)
	{
		memcpy(header, peek_buf, 4);
	}
	/* The length in the RFC NB header is the raw data length */
	return smb_len(peek_buf);
}
Esempio n. 9
0
/*
 * This is called to update the inode attributes after
 * we've made changes to a file or directory.
 */
static int
smb_refresh_inode(struct dentry *dentry)
{
	struct inode *inode = dentry->d_inode;
	int error;
	struct smb_fattr fattr;

	error = smb_proc_getattr(dentry, &fattr);
	if (!error) {
		smb_renew_times(dentry);
		/*
		 * Check whether the type part of the mode changed,
		 * and don't update the attributes if it did.
		 *
		 * And don't dick with the root inode
		 */
		if (inode->i_ino == 2)
			return error;
		if (S_ISLNK(inode->i_mode))
			return error;	/* VFS will deal with it */

		if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
			smb_set_inode_attr(inode, &fattr);
		} else {
			/*
			 * Big trouble! The inode has become a new object,
			 * so any operations attempted on it are invalid.
			 *
			 * To limit damage, mark the inode as bad so that
			 * subsequent lookup validations will fail.
			 */
			PARANOIA("%s/%s changed mode, %07o to %07o\n",
				 DENTRY_PATH(dentry),
				 inode->i_mode, fattr.f_mode);

			fattr.f_mode = inode->i_mode; /* save mode */
			make_bad_inode(inode);
			inode->i_mode = fattr.f_mode; /* restore mode */
			/*
			 * No need to worry about unhashing the dentry: the
			 * lookup validation will see that the inode is bad.
			 * But we do want to invalidate the caches ...
			 */
			if (!S_ISDIR(inode->i_mode))
				invalidate_remote_inode(inode);
			else
				smb_invalid_dir_cache(inode);
			error = -EIO;
		}
	}
	return error;
}
Esempio n. 10
0
/*
 * Called with the server locked.
 */
void
smb_close_socket(struct smb_sb_info *server)
{
	struct file * file = server->sock_file;

	if (file) {
		VERBOSE("closing socket %p\n", server_sock(server));
#ifdef SMBFS_PARANOIA
		if (server_sock(server)->sk->data_ready == smb_data_ready)
			PARANOIA("still catching keepalives!\n");
#endif
		server->sock_file = NULL;
		fput(file);
	}
}
Esempio n. 11
0
static struct socket *
server_sock(struct smb_sb_info *server)
{
	struct file *file;

	if (server && (file = server->sock_file))
	{
#ifdef SMBFS_PARANOIA
		if (!smb_valid_socket(file->f_dentry->d_inode))
			PARANOIA("bad socket!\n");
#endif
		return &file->f_dentry->d_inode->u.socket_i;
	}
	return NULL;
}
Esempio n. 12
0
/*
 * Read a page synchronously.
 */
static int
smb_readpage_sync(struct dentry *dentry, struct page *page)
{
	char *buffer = kmap(page);
	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
	struct smb_sb_info *server = server_from_dentry(dentry);
	unsigned int rsize = smb_get_rsize(server);
	int count = PAGE_SIZE;
	int result;

	VERBOSE("file %s/%s, count=%d@%ld, rsize=%d\n",
		DENTRY_PATH(dentry), count, offset, rsize);

	result = smb_open(dentry, SMB_O_RDONLY);
	if (result < 0) {
		PARANOIA("%s/%s open failed, error=%d\n",
			 DENTRY_PATH(dentry), result);
		goto io_error;
	}

	do {
		if (count < rsize)
			rsize = count;

		result = server->ops->read(dentry->d_inode,offset,rsize,buffer);
		if (result < 0)
			goto io_error;

		count -= result;
		offset += result;
		buffer += result;
		dentry->d_inode->i_atime = CURRENT_TIME;
		if (result < rsize)
			break;
	} while (count);

	memset(buffer, 0, count);
	flush_dcache_page(page);
	SetPageUptodate(page);
	result = 0;

io_error:
	kunmap(page);
	UnlockPage(page);
	return result;
}
Esempio n. 13
0
/* setup to receive the data part of the SMB */
static int smb_setup_bcc(struct smb_request *req)
{
	int result = 0;
	req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;

	if (req->rq_rlen > req->rq_bufsize) {
		PARANOIA("Packet too large %d > %d\n",
			 req->rq_rlen, req->rq_bufsize);
		return -ENOBUFS;
	}

	req->rq_iov[0].iov_base = req->rq_buffer;
	req->rq_iov[0].iov_len  = req->rq_rlen;
	req->rq_iovlen = 1;

	return result;
}
Esempio n. 14
0
static void
smb_data_callback(void* ptr)
{
	struct data_callback* job=ptr;
	struct socket *socket = job->sk->socket;
	unsigned char peek_buf[4];
	int result;
	mm_segment_t fs;

	fs = get_fs();
	set_fs(get_ds());

	lock_kernel();
	while (1)
	{
		result = -EIO;
		if (job->sk->dead)
		{
			PARANOIA("sock dead!\n");
			break;
		}

		result = _recvfrom(socket, (void *) peek_buf, 1,
				   MSG_PEEK | MSG_DONTWAIT);
		if (result == -EAGAIN)
			break;
		if (peek_buf[0] != 0x85)
			break;

		/* got SESSION KEEP ALIVE */
		result = _recvfrom(socket, (void *) peek_buf, 4,
				   MSG_DONTWAIT);

		DEBUG1("got SESSION KEEPALIVE\n");

		if (result == -EAGAIN)
			break;
	}
	unlock_kernel();
	set_fs(fs);

	if (result != -EAGAIN)
		found_data(job->sk);
	kfree(ptr);
}
Esempio n. 15
0
static int
smb_file_mmap(struct file * file, struct vm_area_struct * vma)
{
	struct dentry * dentry = file->f_dentry;
	int	status;

	VERBOSE("file %s/%s, address %lu - %lu\n",
		DENTRY_PATH(dentry), vma->vm_start, vma->vm_end);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%d\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}
	status = generic_file_mmap(file, vma);
out:
	return status;
}
Esempio n. 16
0
/*
 * This is the callback when the dcache has a lookup hit.
 */
static int
smb_lookup_validate(struct dentry *dentry, struct nameidata *nd)
{
	struct smb_sb_info *server;
	struct inode *inode;
	unsigned long age;
	int valid;

	if (nd->flags & LOOKUP_RCU)
		return -ECHILD;

	server = server_from_dentry(dentry);
	inode = dentry->d_inode;
	age = jiffies - dentry->d_time;

	/*
	 * The default validation is based on dentry age:
	 * we believe in dentries for a few seconds.  (But each
	 * successful server lookup renews the timestamp.)
	 */
	valid = (age <= SMB_MAX_AGE(server));
#ifdef SMBFS_DEBUG_VERBOSE
	if (!valid)
		VERBOSE("%s/%s not valid, age=%lu\n", 
			DENTRY_PATH(dentry), age);
#endif

	if (inode) {
		lock_kernel();
		if (is_bad_inode(inode)) {
			PARANOIA("%s/%s has dud inode\n", DENTRY_PATH(dentry));
			valid = 0;
		} else if (!valid)
			valid = (smb_revalidate_inode(dentry) == 0);
		unlock_kernel();
	} else {
		/*
		 * What should we do for negative dentries?
		 */
	}
	return valid;
}
Esempio n. 17
0
static ssize_t
smb_file_sendfile(struct file *file, loff_t *ppos,
		  size_t count, read_actor_t actor, void *target)
{
	struct dentry *dentry = file->f_path.dentry;
	ssize_t status;

	VERBOSE("file %s/%s, pos=%Ld, count=%d\n",
		DENTRY_PATH(dentry), *ppos, count);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}
	status = generic_file_sendfile(file, ppos, count, actor, target);
out:
	return status;
}
Esempio n. 18
0
static ssize_t
smb_file_splice_read(struct file *file, loff_t *ppos,
		     struct pipe_inode_info *pipe, size_t count,
		     unsigned int flags)
{
	struct dentry *dentry = file->f_path.dentry;
	ssize_t status;

	VERBOSE("file %s/%s, pos=%Ld, count=%lu\n",
		DENTRY_PATH(dentry), *ppos, count);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}
	status = generic_file_splice_read(file, ppos, pipe, count, flags);
out:
	return status;
}
Esempio n. 19
0
/*
 * Get a pointer to the cache_head structure,
 * mapped as the page at offset 0. The page is
 * kept locked while we're using the cache.
 */
struct cache_head *
smb_get_dircache(struct dentry * dentry)
{
	struct inode * inode = dentry->d_inode;
	struct cache_head * cachep;

	VERBOSE("finding cache for %s/%s\n", DENTRY_PATH(dentry));
	cachep = (struct cache_head *) get_cached_page(inode, 0, 1);
	if (!cachep)
		goto out;
	if (cachep->valid)
	{
		struct cache_index * index = cachep->index;
		struct cache_block * block;
		unsigned long offset;
		int i;

		cachep->valid = 0;
		/*
		 * Here we only want to find existing cache blocks,
		 * not add new ones.
		 */
		for (i = 0; i < cachep->pages; i++, index++) {
#ifdef SMBFS_PARANOIA
			if (index->block)
				PARANOIA("cache %s/%s has existing block!\n",
					 DENTRY_PATH(dentry));
#endif
			offset = PAGE_SIZE + (i << PAGE_SHIFT);
			block = (struct cache_block *) get_cached_page(inode,
								offset, 0);
			if (!block)
				goto out;
			index->block = block;
		}
		cachep->valid = 1;
	}
out:
	return cachep;
}
Esempio n. 20
0
static ssize_t
smb_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
{
	struct dentry * dentry = file->f_dentry;
	ssize_t	status;

	VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
		(unsigned long) count, (unsigned long) *ppos);

	status = smb_revalidate_inode(dentry);
	if (status) {
		PARANOIA("%s/%s validation failed, error=%Zd\n",
			 DENTRY_PATH(dentry), status);
		goto out;
	}

	VERBOSE("before read, size=%ld, flags=%x, atime=%ld\n",
		(long)dentry->d_inode->i_size,
		dentry->d_inode->i_flags, dentry->d_inode->i_atime);

	status = generic_file_read(file, buf, count, ppos);
out:
	return status;
}
Esempio n. 21
0
/*
 * Add a new entry to the cache.  This assumes that the
 * entries are coming in order and are added to the end.
 */
void
smb_add_to_cache(struct cache_head * cachep, struct cache_dirent *entry,
			off_t fpos)
{
	struct inode * inode = get_cache_inode(cachep);
	struct cache_index * index;
	struct cache_block * block;
	unsigned long page_off;
	unsigned int nent, offset, len = entry->len;
	unsigned int needed = len + sizeof(struct cache_entry);

	VERBOSE("cache inode %p, status %d, adding %.*s at %ld\n",
		inode, cachep->status, entry->len, entry->name, fpos);
	/*
	 * Don't do anything if we've had an error ...
	 */
	if (cachep->status)
		goto out;

	index = &cachep->index[cachep->idx];
	if (!index->block)
		goto get_block;

	/* space available? */
	if (needed < index->space)
	{
	add_entry:
		nent = index->num_entries;
		index->num_entries++;
		index->space -= needed;
		offset = index->space + 
			 index->num_entries * sizeof(struct cache_entry);
		block = index->block;
		memcpy(&block->cb_data.names[offset], entry->name, len);
		block->cb_data.table[nent].namelen = len;
		block->cb_data.table[nent].offset = offset;
		block->cb_data.table[nent].ino = entry->ino;
		cachep->entries++;
		VERBOSE("added entry %.*s, len=%d, pos=%ld, entries=%d\n",
			entry->len, entry->name, len, fpos, cachep->entries);
		return;
	}
	/*
	 * This block is full ... advance the index.
	 */
	cachep->idx++;
	if (cachep->idx > NINDEX) /* not likely */
		goto out_full;
	index++;
#ifdef SMBFS_PARANOIA
	if (index->block)
		PARANOIA("new index already has block!\n");
#endif

	/*
	 * Get the next cache block
	 */
get_block:
	cachep->pages++;
	page_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT);
	block = (struct cache_block *) get_cached_page(inode, page_off, 1);
	if (block)
	{
		index->block = block;
		index->space = PAGE_SIZE;
		VERBOSE("inode=%p, pages=%d, block at %ld\n",
			inode, cachep->pages, page_off);
		goto add_entry;
	}
	/*
	 * On failure, just set the return status ...
	 */
out_full:
	cachep->status = -ENOMEM;
out:
	return;
}
Esempio n. 22
0
/*
 * This routine checks first for "fast track" processing, as most
 * packets won't need to be copied. Otherwise, it allocates a new
 * packet to hold the incoming data.
 *
 * Note that the final server packet must be the larger of the two;
 * server packets aren't allowed to shrink.
 */
static int
smb_receive_trans2(struct smb_sb_info *server,
		   int *ldata, unsigned char **data,
		   int *lparm, unsigned char **parm)
{
	unsigned char *inbuf, *base, *rcv_buf = NULL;
	unsigned int parm_disp, parm_offset, parm_count, parm_tot, parm_len = 0;
	unsigned int data_disp, data_offset, data_count, data_tot, data_len = 0;
	unsigned int total_p = 0, total_d = 0, buf_len = 0;
	int result;

	while (1)
	{
		result = smb_receive(server);
		if (result < 0)
			goto out;
		inbuf = server->packet;
		if (server->rcls != 0)
		{
			*parm = *data = inbuf;
			*ldata = *lparm = 0;
			goto out;
		}
		/*
		 * Extract the control data from the packet.
		 */
		data_tot    = WVAL(inbuf, smb_tdrcnt);
		parm_tot    = WVAL(inbuf, smb_tprcnt);
		parm_disp   = WVAL(inbuf, smb_prdisp);
		parm_offset = WVAL(inbuf, smb_proff);
		parm_count  = WVAL(inbuf, smb_prcnt);
		data_disp   = WVAL(inbuf, smb_drdisp);
		data_offset = WVAL(inbuf, smb_droff);
		data_count  = WVAL(inbuf, smb_drcnt);
		base = smb_base(inbuf);

		/*
		 * Assume success and increment lengths.
		 */
		parm_len += parm_count;
		data_len += data_count;

		if (!rcv_buf)
		{
			/*
			 * Check for fast track processing ... just this packet.
			 */
			if (parm_count == parm_tot && data_count == data_tot)
			{
				VERBOSE("fast track, parm=%u %u %u, data=%u %u %u\n",
					parm_disp, parm_offset, parm_count, 
					data_disp, data_offset, data_count);

				*parm  = base + parm_offset;
				*data  = base + data_offset;
				goto success;
			}

			if (parm_tot > TRANS2_MAX_TRANSFER ||
	  		    data_tot > TRANS2_MAX_TRANSFER)
				goto out_too_long;

			/*
			 * Save the total parameter and data length.
			 */
			total_d = data_tot;
			total_p = parm_tot;

			buf_len = total_d + total_p;
			if (server->packet_size > buf_len)
				buf_len = server->packet_size;
			buf_len = smb_round_length(buf_len);

			rcv_buf = smb_vmalloc(buf_len);
			if (!rcv_buf)
				goto out_no_mem;
			*parm = rcv_buf;
			*data = rcv_buf + total_p;
		}
		else if (data_tot > total_d || parm_tot > total_p)
			goto out_data_grew;

		if (parm_disp + parm_count > total_p)
			goto out_bad_parm;
		if (data_disp + data_count > total_d)
			goto out_bad_data;
		memcpy(*parm + parm_disp, base + parm_offset, parm_count);
		memcpy(*data + data_disp, base + data_offset, data_count);

		PARANOIA("copied, parm=%u of %u, data=%u of %u\n",
			 parm_len, parm_tot, data_len, data_tot);

		/*
		 * Check whether we've received all of the data. Note that
		 * we use the packet totals -- total lengths might shrink!
		 */
		if (data_len >= data_tot && parm_len >= parm_tot)
			break;
	}

	/*
	 * Install the new packet.  Note that it's possible, though
	 * unlikely, that the new packet could be smaller than the
	 * old one, in which case we just copy the data.
	 */
	inbuf = server->packet;
	if (buf_len >= server->packet_size)
	{
		server->packet_size = buf_len;
		server->packet = rcv_buf;
		rcv_buf = inbuf;
	} else {
		PARANOIA("copying data, old size=%d, new size=%u\n",
			 server->packet_size, buf_len);
		memcpy(inbuf, rcv_buf, parm_len + data_len);
	}

success:
	*ldata = data_len;
	*lparm = parm_len;
out:
	if (rcv_buf)
		smb_vfree(rcv_buf);
	return result;

out_no_mem:
	printk(KERN_ERR "smb_receive_trans2: couldn't allocate data area\n");
	result = -ENOMEM;
	goto out;
out_too_long:
	printk(KERN_ERR "smb_receive_trans2: data/param too long, data=%d, parm=%d\n",
	       data_tot, parm_tot);
	goto out_error;
out_data_grew:
	printk(KERN_ERR "smb_receive_trans2: data/params grew!\n");
	goto out_error;
out_bad_parm:
	printk(KERN_ERR "smb_receive_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n",
	       parm_disp, parm_count, parm_tot);
	goto out_error;
out_bad_data:
	printk(KERN_ERR "smb_receive_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n",
	       data_disp, data_count, data_tot);
out_error:
	result = -EIO;
	goto out;
}
Esempio n. 23
0
/*
 * Called with the server locked
 */
int
smb_request(struct smb_sb_info *server)
{
	unsigned long flags, sigpipe;
	mm_segment_t fs;
	sigset_t old_set;
	int len, result;
	unsigned char *buffer;

	result = -EBADF;
	buffer = server->packet;
	if (!buffer)
		goto bad_no_packet;

	result = -EIO;
	if (server->state != CONN_VALID)
		goto bad_no_conn;

	if ((result = smb_dont_catch_keepalive(server)) != 0)
		goto bad_conn;

	len = smb_len(buffer) + 4;
	DEBUG1("len = %d cmd = 0x%X\n", len, buffer[8]);

	spin_lock_irqsave(&current->sigmask_lock, flags);
	sigpipe = sigismember(&current->signal, SIGPIPE);
	old_set = current->blocked;
	siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
	recalc_sigpending(current);
	spin_unlock_irqrestore(&current->sigmask_lock, flags);

	fs = get_fs();
	set_fs(get_ds());

	result = smb_send_raw(server_sock(server), (void *) buffer, len);
	if (result > 0)
	{
		result = smb_receive(server);
	}

	/* read/write errors are handled by errno */
	spin_lock_irqsave(&current->sigmask_lock, flags);
	if (result == -EPIPE && !sigpipe)
		sigdelset(&current->signal, SIGPIPE);
	current->blocked = old_set;
	recalc_sigpending(current);
	spin_unlock_irqrestore(&current->sigmask_lock, flags);

	set_fs(fs);

	if (result >= 0)
	{
		int result2 = smb_catch_keepalive(server);
		if (result2 < 0)
		{
			printk(KERN_ERR "smb_request: catch keepalive failed\n");
			result = result2;
		}
	}
	if (result < 0)
		goto bad_conn;
	/*
	 * Check for fatal server errors ...
	 */
	if (server->rcls) {
		int error = smb_errno(server);
		if (error == EBADSLT) {
			printk(KERN_ERR "smb_request: tree ID invalid\n");
			result = error;
			goto bad_conn;
		}
	}

out:
	DEBUG1("result = %d\n", result);
	return result;
	
bad_conn:
	PARANOIA("result %d, setting invalid\n", result);
	server->state = CONN_INVALID;
	smb_invalidate_inodes(server);
	goto out;
bad_no_packet:
	printk(KERN_ERR "smb_request: no packet!\n");
	goto out;
bad_no_conn:
	printk(KERN_ERR "smb_request: connection %d not valid!\n",
	       server->state);
	goto out;
}
Esempio n. 24
0
/*
 * This is not really a trans2 request, we assume that you only have
 * one packet to send.
 */
int
smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
		   int ldata, unsigned char *data,
		   int lparam, unsigned char *param,
		   int *lrdata, unsigned char **rdata,
		   int *lrparam, unsigned char **rparam)
{
	sigset_t old_set;
	unsigned long flags, sigpipe;
	mm_segment_t fs;
	int result;

	DEBUG1("com=%d, ld=%d, lp=%d\n", trans2_command, ldata, lparam);

	/*
	 * These are initialized in smb_request_ok, but not here??
	 */
	server->rcls = 0;
	server->err = 0;

	result = -EIO;
	if (server->state != CONN_VALID)
		goto out;

	if ((result = smb_dont_catch_keepalive(server)) != 0)
		goto bad_conn;

	spin_lock_irqsave(&current->sigmask_lock, flags);
	sigpipe = sigismember(&current->signal, SIGPIPE);
	old_set = current->blocked;
	siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
	recalc_sigpending(current);
	spin_unlock_irqrestore(&current->sigmask_lock, flags);

	fs = get_fs();
	set_fs(get_ds());

	result = smb_send_trans2(server, trans2_command,
				 ldata, data, lparam, param);
	if (result >= 0)
	{
		result = smb_receive_trans2(server,
					    lrdata, rdata, lrparam, rparam);
	}

	/* read/write errors are handled by errno */
	spin_lock_irqsave(&current->sigmask_lock, flags);
	if (result == -EPIPE && !sigpipe)
		sigdelset(&current->signal, SIGPIPE);
	current->blocked = old_set;
	recalc_sigpending(current);
	spin_unlock_irqrestore(&current->sigmask_lock, flags);

	set_fs(fs);

	if (result >= 0)
	{
		int result2 = smb_catch_keepalive(server);
		if (result2 < 0)
		{
			result = result2;
		}
	}
	if (result < 0)
		goto bad_conn;
	/*
	 * Check for fatal server errors ...
	 */
	if (server->rcls) {
		int error = smb_errno(server);
		if (error == EBADSLT) {
			printk(KERN_ERR "smb_request: tree ID invalid\n");
			result = error;
			goto bad_conn;
		}
	}

out:
	return result;

bad_conn:
	PARANOIA("result=%d, setting invalid\n", result);
	server->state = CONN_INVALID;
	smb_invalidate_inodes(server);
	goto out;
}
Esempio n. 25
0
/*
 * Add a request and tell smbiod to process it
 */
int smb_add_request(struct smb_request *req)
{
	long timeleft;
	struct smb_sb_info *server = req->rq_server;
	int result = 0;

	smb_setup_request(req);
	if (req->rq_trans2_command) {
		if (req->rq_buffer == NULL) {
			PARANOIA("trans2 attempted without response buffer!\n");
			return -EIO;
		}
		result = smb_setup_trans2request(req);
	}
	if (result < 0)
		return result;

#ifdef SMB_DEBUG_PACKET_SIZE
	add_xmit_stats(req);
#endif

	/* add 'req' to the queue of requests */
	if (smb_lock_server_interruptible(server))
		return -EINTR;

	/*
	 * Try to send the request as the process. If that fails we queue the
	 * request and let smbiod send it later.
	 */

	/* FIXME: each server has a number on the maximum number of parallel
	   requests. 10, 50 or so. We should not allow more requests to be
	   active. */
	if (server->mid > 0xf000)
		server->mid = 0;
	req->rq_mid = server->mid++;
	WSET(req->rq_header, smb_mid, req->rq_mid);

	result = 0;
	if (server->state == CONN_VALID) {
		if (list_empty(&server->xmitq))
			result = smb_request_send_req(req);
		if (result < 0) {
			/* Connection lost? */
			server->conn_error = result;
			server->state = CONN_INVALID;
		}
	}
	if (result != 1)
		list_add_tail(&req->rq_queue, &server->xmitq);
	smb_rget(req);

	if (server->state != CONN_VALID)
		smbiod_retry(server);

	smb_unlock_server(server);

	smbiod_wake_up();

	timeleft = wait_event_interruptible_timeout(req->rq_wait,
				    req->rq_flags & SMB_REQ_RECEIVED, 30*HZ);
	if (!timeleft || signal_pending(current)) {
		/*
		 * On timeout or on interrupt we want to try and remove the
		 * request from the recvq/xmitq.
		 * First check if the request is still part of a queue. (May
		 * have been removed by some error condition)
		 */
		smb_lock_server(server);
		if (!list_empty(&req->rq_queue)) {
			list_del_init(&req->rq_queue);
			smb_rput(req);
		}
		smb_unlock_server(server);
	}

	if (!timeleft) {
		PARANOIA("request [%p, mid=%d] timed out!\n",
			 req, req->rq_mid);
		VERBOSE("smb_com:  %02x\n", *(req->rq_header + smb_com));
		VERBOSE("smb_rcls: %02x\n", *(req->rq_header + smb_rcls));
		VERBOSE("smb_flg:  %02x\n", *(req->rq_header + smb_flg));
		VERBOSE("smb_tid:  %04x\n", WVAL(req->rq_header, smb_tid));
		VERBOSE("smb_pid:  %04x\n", WVAL(req->rq_header, smb_pid));
		VERBOSE("smb_uid:  %04x\n", WVAL(req->rq_header, smb_uid));
		VERBOSE("smb_mid:  %04x\n", WVAL(req->rq_header, smb_mid));
		VERBOSE("smb_wct:  %02x\n", *(req->rq_header + smb_wct));

		req->rq_rcls = ERRSRV;
		req->rq_err  = ERRtimeout;

		/* Just in case it was "stuck" */
		smbiod_wake_up();
	}
	VERBOSE("woke up, rcls=%d\n", req->rq_rcls);

	if (req->rq_rcls != 0)
		req->rq_errno = smb_errno(req);
	if (signal_pending(current))
		req->rq_errno = -ERESTARTSYS;
	return req->rq_errno;
}