Beispiel #1
0
int
frontend_changed(vbd_t * const device, const XenbusState state)
{
    int err = 0;

    DBG(device, "front-end went into state %s\n", xenbus_strstate(state));
	device->frontend_state = state;

    switch (state) {
        case XenbusStateInitialising:
			if (device->hotplug_status_connected)
				err = xenbus_switch_state(device, XenbusStateInitWait);
            break;
        case XenbusStateInitialised:
    	case XenbusStateConnected:
            /*
             * Already connected when the front-end switched to Initialising?
             */
            if (device->hotplug_status_connected
					&& device->state != XenbusStateConnected)
                err = connect(device);
            break;
        case XenbusStateClosing:
            err = xenbus_switch_state(device, XenbusStateClosing);
            break;
        case XenbusStateClosed:
            err = backend_close(device);
            break;
        default:
            err = EINVAL;
            WARN(device, "invalid front-end state %d", state);
            break;
    }
    return err;
}
Beispiel #2
0
/*
 * close a file descriptor
 * returns error number from real close() if applicable
 */
int fd_close(int fd, int kind, int really_close)
{
    int idx, res1 = 0, res2 = 0;

    idx = idx_by_fd(fd, kind);
    if (idx != -1) {
	/* update usage time of cache entry */
	fd_cache[idx].use = time(NULL);

	if (really_close == FD_CLOSE_REAL)
	    /* delete entry on real close, will close() fd */
	    return fd_cache_del(idx, FALSE);
	else
	    return 0;
    } else {
	/* not in cache, sync and close directly */
	if (kind == UNFS3_FD_WRITE)
	    res1 = backend_fsync(fd);

	res2 = backend_close(fd);

	if (res1 != 0)
	    return res1;
	else
	    return res2;
    }
}
Beispiel #3
0
/*
 * open a file descriptor
 * uses fd from cache if possible
 */
int fd_open(const char *path, nfs_fh3 nfh, int kind, int allow_caching)
{
    int idx, res, fd;
    backend_statstruct buf;
    unfs3_fh_t *fh = (void *) nfh.data.data_val;

    idx = idx_by_fh(fh, kind);

    if (idx != -1) {
	if (fd_cache[idx].fd == -1) {
	    /* pending error, report to client and remove from cache */
	    fd_cache_del(idx, FALSE);
	    return -1;
	}
	return fd_cache[idx].fd;
    } else {
	/* call open to obtain new fd */
	if (kind == UNFS3_FD_READ)
	    fd = backend_open(path, O_RDONLY);
	else
	    fd = backend_open(path, O_WRONLY);
	if (fd == -1)
	    return -1;

	/* check for local fs race */
	res = backend_fstat(fd, &buf);
	if ((res == -1) ||
	    (fh->dev != buf.st_dev || fh->ino != buf.st_ino ||
	     fh->gen != backend_get_gen(buf, fd, path))) {
	    /* 
	     * local fs changed meaning of path between
	     * calling NFS operation doing fh_decomp and
	     * arriving here
	     *
	     * set errno to ELOOP to make calling NFS
	     * operation return NFS3ERR_STALE
	     */
	    backend_close(fd);
	    errno = ELOOP;
	    return -1;
	}

	/* 
	 * success, add to cache for later use
	 */
	if (allow_caching)
	    fd_cache_add(fd, fh, kind);
	return fd;
    }
}
Beispiel #4
0
/*

 * remove an entry from the cache. The keep_on_error variable
 * indicates if the entry should be kept in the cache upon
 * fsync/close failures. It should be set to TRUE when fd_cache_del is
 * called from a code path which cannot report an IO error back to the
 * client through WRITE or COMMIT. 
 */
static int fd_cache_del(int idx, int keep_on_error)
{
    int res1, res2;

    res1 = -1;

    if (fd_cache[idx].fd != -1) {
	if (fd_cache[idx].kind == UNFS3_FD_WRITE) {
	    /* sync file data if writing descriptor */
	    fd_cache_writers--;
	    res1 = backend_fsync(fd_cache[idx].fd);
	} else {
	    fd_cache_readers--;
	    res1 = 0;
	}
	res2 = backend_close(fd_cache[idx].fd);
	fd_cache[idx].fd = -1;

	/* return -1 if something went wrong during sync or close */
	if (res1 == -1 || res2 == -1) {
	    res1 = -1;
	}
    } else
	/* pending error */
	errno = EIO;

    if (res1 == -1 && !keep_on_error) {
	/* The verifier should not be changed until we actually report &
	   remove the error */
	regenerate_write_verifier();
    }

    if (res1 != -1 || !keep_on_error) {
	fd_cache[idx].fd = -1;
	fd_cache[idx].use = 0;
	fd_cache[idx].dev = 0;
	fd_cache[idx].ino = 0;
	fd_cache[idx].gen = 0;
    }

    return res1;
}
Beispiel #5
0
CREATE3res *nfsproc3_create_3_svc(CREATE3args * argp, struct svc_req * rqstp)
{
    static CREATE3res result;
    char *path;
    char obj[NFS_MAXPATHLEN];
    sattr3 new_attr;
    int fd = -1, res = -1;
    backend_statstruct buf;
    uint32 gen;
    int flags = O_RDWR | O_CREAT | O_TRUNC | O_NONBLOCK;

    PREP(path, argp->where.dir);
    result.status = join(cat_name(path, argp->where.name, obj), exports_rw());

    cluster_create(obj, rqstp, &result.status);

    /* GUARDED and EXCLUSIVE maps to Unix exclusive create */
    if (argp->how.mode != UNCHECKED)
	flags = flags | O_EXCL;

    if (argp->how.mode != EXCLUSIVE) {
	new_attr = argp->how.createhow3_u.obj_attributes;
	result.status = join(result.status, atomic_attr(new_attr));
    }

    /* Try to open the file */
    if (result.status == NFS3_OK) {
	if (argp->how.mode != EXCLUSIVE) {
	    fd = backend_open_create(obj, flags, create_mode(new_attr));
	} else {
	    fd = backend_open_create(obj, flags, create_mode(new_attr));
	}
    }

    if (fd != -1) {
	/* Successful open */
	res = backend_fstat(fd, &buf);
	if (res != -1) {
	    /* Successful stat */
	    if (argp->how.mode == EXCLUSIVE) {
		/* Save verifier in atime and mtime */
		res =
		    backend_store_create_verifier(obj,
						  argp->how.createhow3_u.
						  verf);
	    }
	}

	if (res != -1) {
	    /* So far, so good */
	    gen = backend_get_gen(buf, fd, obj);
	    fh_cache_add(buf.st_dev, buf.st_ino, obj);
	    backend_close(fd);

	    result.CREATE3res_u.resok.obj =
		fh_extend_post(argp->where.dir, buf.st_dev, buf.st_ino, gen);
	    result.CREATE3res_u.resok.obj_attributes =
		get_post_buf(buf, rqstp);
	}

	if (res == -1) {
	    /* backend_fstat() or backend_store_create_verifier() failed */
	    backend_close(fd);
	    result.status = NFS3ERR_IO;
	}

    } else if (result.status == NFS3_OK) {
	/* open() failed */
	if (argp->how.mode == EXCLUSIVE && errno == EEXIST) {
	    /* Check if verifier matches */
	    fd = backend_open(obj, O_NONBLOCK);
	    if (fd != -1) {
		res = backend_fstat(fd, &buf);
	    }

	    if (res != -1) {
		if (backend_check_create_verifier
		    (&buf, argp->how.createhow3_u.verf)) {
		    /* The verifier matched. Return success */
		    gen = backend_get_gen(buf, fd, obj);
		    fh_cache_add(buf.st_dev, buf.st_ino, obj);
		    backend_close(fd);

		    result.CREATE3res_u.resok.obj =
			fh_extend_post(argp->where.dir, buf.st_dev,
				       buf.st_ino, gen);
		    result.CREATE3res_u.resok.obj_attributes =
			get_post_buf(buf, rqstp);
		} else {
		    /* The verifier doesn't match */
		    result.status = NFS3ERR_EXIST;
		}
	    }
	}
	if (res == -1) {
	    result.status = create_err();
	}
    }

    /* overlaps with resfail */
    result.CREATE3res_u.resok.dir_wcc.before = get_pre_cached();
    result.CREATE3res_u.resok.dir_wcc.after = get_post_stat(path, rqstp);

    return &result;
}