Example #1
0
int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr,
		      const struct rpc_call_ops *call_ops, int how, int flags)
{
	struct rpc_task *task;
	struct rpc_message msg = {
		.rpc_argp = &hdr->args,
		.rpc_resp = &hdr->res,
		.rpc_cred = hdr->cred,
	};
	struct rpc_task_setup task_setup_data = {
		.rpc_client = clnt,
		.task = &hdr->task,
		.rpc_message = &msg,
		.callback_ops = call_ops,
		.callback_data = hdr,
		.workqueue = nfsiod_workqueue,
		.flags = RPC_TASK_ASYNC | flags,
	};
	int ret = 0;

	hdr->rw_ops->rw_initiate(hdr, &msg, &task_setup_data, how);

	dprintk("NFS: %5u initiated pgio call "
		"(req %s/%llu, %u bytes @ offset %llu)\n",
		hdr->task.tk_pid,
		hdr->inode->i_sb->s_id,
		(unsigned long long)NFS_FILEID(hdr->inode),
		hdr->args.count,
		(unsigned long long)hdr->args.offset);

	task = rpc_run_task(&task_setup_data);
	if (IS_ERR(task)) {
		ret = PTR_ERR(task);
		goto out;
	}
	if (how & FLUSH_SYNC) {
		ret = rpc_wait_for_completion_task(task);
		if (ret == 0)
			ret = task->tk_status;
	}
	rpc_put_task(task);
out:
	return ret;
}
EXPORT_SYMBOL_GPL(nfs_initiate_pgio);

/**
 * nfs_pgio_error - Clean up from a pageio error
 * @desc: IO descriptor
 * @hdr: pageio header
 */
static int nfs_pgio_error(struct nfs_pageio_descriptor *desc,
			  struct nfs_pgio_header *hdr)
{
	set_bit(NFS_IOHDR_REDO, &hdr->flags);
	nfs_pgio_data_destroy(hdr);
	hdr->completion_ops->completion(hdr);
	desc->pg_completion_ops->error_cleanup(&desc->pg_list);
	return -ENOMEM;
}

/**
 * nfs_pgio_release - Release pageio data
 * @calldata: The pageio header to release
 */
static void nfs_pgio_release(void *calldata)
{
	struct nfs_pgio_header *hdr = calldata;
	if (hdr->rw_ops->rw_release)
		hdr->rw_ops->rw_release(hdr);
	nfs_pgio_data_destroy(hdr);
	hdr->completion_ops->completion(hdr);
}

/**
 * nfs_pageio_init - initialise a page io descriptor
 * @desc: pointer to descriptor
 * @inode: pointer to inode
 * @doio: pointer to io function
 * @bsize: io block size
 * @io_flags: extra parameters for the io function
 */
void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
		     struct inode *inode,
		     const struct nfs_pageio_ops *pg_ops,
		     const struct nfs_pgio_completion_ops *compl_ops,
		     const struct nfs_rw_ops *rw_ops,
		     size_t bsize,
		     int io_flags)
{
	INIT_LIST_HEAD(&desc->pg_list);
	desc->pg_bytes_written = 0;
	desc->pg_count = 0;
	desc->pg_bsize = bsize;
	desc->pg_base = 0;
	desc->pg_moreio = 0;
	desc->pg_recoalesce = 0;
	desc->pg_inode = inode;
	desc->pg_ops = pg_ops;
	desc->pg_completion_ops = compl_ops;
	desc->pg_rw_ops = rw_ops;
	desc->pg_ioflags = io_flags;
	desc->pg_error = 0;
	desc->pg_lseg = NULL;
	desc->pg_dreq = NULL;
	desc->pg_layout_private = NULL;
}
Example #2
0
/**
 * nfs_sillyrename - Perform a silly-rename of a dentry
 * @dir: inode of directory that contains dentry
 * @dentry: dentry to be sillyrenamed
 *
 * NFSv2/3 is stateless and the server doesn't know when the client is
 * holding a file open. To prevent application problems when a file is
 * unlinked while it's still open, the client performs a "silly-rename".
 * That is, it renames the file to a hidden file in the same directory,
 * and only performs the unlink once the last reference to it is put.
 *
 * The final cleanup is done during dentry_iput.
 *
 * (Note: NFSv4 is stateful, and has opens, so in theory an NFSv4 server
 * could take responsibility for keeping open files referenced.  The server
 * would also need to ensure that opened-but-deleted files were kept over
 * reboots.  However, we may not assume a server does so.  (RFC 5661
 * does provide an OPEN4_RESULT_PRESERVE_UNLINKED flag that a server can
 * use to advertise that it does this; some day we may take advantage of
 * it.))
 */
int
nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
    static unsigned int sillycounter;
    const int      fileidsize  = sizeof(NFS_FILEID(dentry->d_inode))*2;
    const int      countersize = sizeof(sillycounter)*2;
    const int      slen        = sizeof(".nfs")+fileidsize+countersize-1;
    char           silly[slen+1];
    struct dentry *sdentry;
    struct rpc_task *task;
    int            error = -EIO;

    dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
             dentry->d_parent->d_name.name, dentry->d_name.name,
             dentry->d_count);
    nfs_inc_stats(dir, NFSIOS_SILLYRENAME);

    /*
     * We don't allow a dentry to be silly-renamed twice.
     */
    error = -EBUSY;
    if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
        goto out;

    sprintf(silly, ".nfs%*.*Lx",
            fileidsize, fileidsize,
            (unsigned long long)NFS_FILEID(dentry->d_inode));

    /* Return delegation in anticipation of the rename */
    NFS_PROTO(dentry->d_inode)->return_delegation(dentry->d_inode);

    sdentry = NULL;
    do {
        char *suffix = silly + slen - countersize;

        dput(sdentry);
        sillycounter++;
        sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);

        dfprintk(VFS, "NFS: trying to rename %s to %s\n",
                 dentry->d_name.name, silly);

        sdentry = lookup_one_len(silly, dentry->d_parent, slen);
        /*
         * N.B. Better to return EBUSY here ... it could be
         * dangerous to delete the file while it's in use.
         */
        if (IS_ERR(sdentry))
            goto out;
    } while (sdentry->d_inode != NULL); /* need negative lookup */

    /* queue unlink first. Can't do this from rpc_release as it
     * has to allocate memory
     */
    error = nfs_async_unlink(dir, dentry);
    if (error)
        goto out_dput;

    /* populate unlinkdata with the right dname */
    error = nfs_copy_dname(sdentry,
                           (struct nfs_unlinkdata *)dentry->d_fsdata);
    if (error) {
        nfs_cancel_async_unlink(dentry);
        goto out_dput;
    }

    /* run the rename task, undo unlink if it fails */
    task = nfs_async_rename(dir, dir, dentry, sdentry);
    if (IS_ERR(task)) {
        error = -EBUSY;
        nfs_cancel_async_unlink(dentry);
        goto out_dput;
    }

    /* wait for the RPC task to complete, unless a SIGKILL intervenes */
    error = rpc_wait_for_completion_task(task);
    if (error == 0)
        error = task->tk_status;
    switch (error) {
    case 0:
        /* The rename succeeded */
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        d_move(dentry, sdentry);
        break;
    case -ERESTARTSYS:
        /* The result of the rename is unknown. Play it safe by
         * forcing a new lookup */
        d_drop(dentry);
        d_drop(sdentry);
    }
    rpc_put_task(task);
out_dput:
    dput(sdentry);
out:
    return error;
}
Example #3
0
int
nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
	static unsigned int sillycounter;
	const int      fileidsize  = sizeof(NFS_FILEID(dentry->d_inode))*2;
	const int      countersize = sizeof(sillycounter)*2;
	const int      slen        = sizeof(".nfs")+fileidsize+countersize-1;
	char           silly[slen+1];
	struct dentry *sdentry;
	struct rpc_task *task;
	int            error = -EIO;

	dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
		dentry->d_parent->d_name.name, dentry->d_name.name,
		dentry->d_count);
	nfs_inc_stats(dir, NFSIOS_SILLYRENAME);

	error = -EBUSY;
	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
		goto out;

	sprintf(silly, ".nfs%*.*Lx",
		fileidsize, fileidsize,
		(unsigned long long)NFS_FILEID(dentry->d_inode));

	
	nfs_inode_return_delegation(dentry->d_inode);

	sdentry = NULL;
	do {
		char *suffix = silly + slen - countersize;

		dput(sdentry);
		sillycounter++;
		sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);

		dfprintk(VFS, "NFS: trying to rename %s to %s\n",
				dentry->d_name.name, silly);

		sdentry = lookup_one_len(silly, dentry->d_parent, slen);
		if (IS_ERR(sdentry))
			goto out;
	} while (sdentry->d_inode != NULL); 

	error = nfs_async_unlink(dir, dentry);
	if (error)
		goto out_dput;

	
	error = nfs_copy_dname(sdentry,
				(struct nfs_unlinkdata *)dentry->d_fsdata);
	if (error) {
		nfs_cancel_async_unlink(dentry);
		goto out_dput;
	}

	
	task = nfs_async_rename(dir, dir, dentry, sdentry);
	if (IS_ERR(task)) {
		error = -EBUSY;
		nfs_cancel_async_unlink(dentry);
		goto out_dput;
	}

	
	error = rpc_wait_for_completion_task(task);
	if (error == 0)
		error = task->tk_status;
	switch (error) {
	case 0:
		/* The rename succeeded */
		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
		d_move(dentry, sdentry);
		break;
	case -ERESTARTSYS:
		/* The result of the rename is unknown. Play it safe by
		 * forcing a new lookup */
		d_drop(dentry);
		d_drop(sdentry);
	}
	rpc_put_task(task);
out_dput:
	dput(sdentry);
out:
	return error;
}