view src/objstore/obj_open.c @ 899:b14fd508b72a

objstore: rename obj_ops.c to obj_open.c This is a better name for a file that contains objstore_{open,close}. Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Mon, 19 Dec 2022 19:55:24 -0500
parents src/objstore/obj_ops.c@cbeaf88784a3
children
line wrap: on
line source

/*
 * Copyright (c) 2015-2020,2022 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "objstore_impl.h"

struct objstore_open_obj_info *objstore_open(struct objstore *vol,
					     const struct noid *oid,
					     const struct nvclock *clock)
{
	struct objstore_open_obj_info *open;
	struct objver *objver;
	struct obj *obj;
	bool qualified;
	int ret;

	if (!vol || !oid || !clock)
		return ERR_PTR(-EINVAL);

	objver = objver_by_clock(vol->clone, oid, clock);
	if (IS_ERR(objver))
		return ERR_CAST(objver);

	qualified = !nvclock_is_null(clock);

	obj = objver->obj;
	open = objver->open[qualified];

	if (!open) {
		/* first open */
		open = mem_cache_alloc(open_obj_cache);
		if (!open) {
			ret = -ENOMEM;
			goto err;
		}

		if (obj->ops && obj->ops->open)
			ret = obj->ops->open(objver);
		else
			ret = 0;

		if (ret)
			goto err_free;

		open->obj = obj;
		open->qualified = qualified;
		open->ver = objver;
		open->open_count = 0; /* will be incremented below */
		open->cow.needed = true;

		objver->open[qualified] = open;
	}

	ASSERT(objver->open[qualified]);

	open->open_count++;

	/*
	 * The object associated with 'objver' is locked and held.  We
	 * unlock it, but keep the hold on it.  Then we return the pointer
	 * to the objver to the caller.  Then, later on when the caller
	 * calls the close function, we release the object's hold.
	 *
	 * While the object version is open, we maintain this reference hold
	 * keeping the object and the version structures in memory.  Even if
	 * all links are removed, we keep the structures around and let
	 * operations use them.  This mimics the POSIX file system semantics
	 * well.
	 */

	MXUNLOCK(&obj->lock);

	return open;

err_free:
	mem_cache_free(open_obj_cache, open);

err:
	MXUNLOCK(&obj->lock);

	obj_putref(obj);

	return ERR_PTR(ret);
}

int objstore_close(struct objstore_open_obj_info *open)
{
	struct obj *obj;
	bool putref;
	int ret;

	if (!open)
		return -EINVAL;

	obj = open->obj;

	MXLOCK(&obj->lock);
	open->open_count--;
	putref = true;

	if (open->open_count) {
		ret = 0;
		putref = false;
	} else if (obj->ops && obj->ops->close) {
		/* last close */
		ret = obj->ops->close(open->ver);
	} else {
		ret = 0;
	}

	if (putref && !ret)
		open->ver->open[open->qualified] = NULL;
	else if (ret)
		open->open_count++; /* undo earlier decrement */
	MXUNLOCK(&obj->lock);

	/* release the reference obtained in objstore_open() */
	if (putref && !ret) {
		mem_cache_free(open_obj_cache, open);
		obj_putref(obj);
	}

	return ret;
}