blob: b50466c2d5b285f120c4a1f4e23c8ad1b74b84da [file] [log] [blame] [raw]
/*
* Copyright (C) 2000-2009, Parallels, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mount.h>
#include "fs.h"
#include "util.h"
#include "logger.h"
#include "vzerror.h"
#include "script.h"
#include "quota.h"
int vps_is_run(vps_handler *h, envid_t veid);
/** Get CT mount status.
*
* @param root CT root.
* @return 1 - CT mounted
* 0 - CT unmounted.
* -1 - error
*/
int vps_is_mounted(const char *root)
{
return vz_fs_is_mounted(root);
}
/** Mount CT.
*
* @param veid CT ID.
* @param fs file system parameters.
* @param dq disk quota parameters.
* @return 0 on success.
*/
int fsmount(envid_t veid, fs_param *fs, dq_param *dq)
{
int ret;
/* Create VE_ROOT mount point if not exist */
if (make_dir(fs->root, 1)) {
logger(-1, 0, "Can't create mount point %s", fs->root);
return VZ_FS_MPOINTCREATE;
}
if ((ret = vps_quotaon(veid, fs->private, dq)))
return ret;
if ((ret = vz_mount(fs, 0)))
vps_quotaoff(veid, dq);
return ret;
}
static int real_umount(envid_t veid, const char *root)
{
int i, ret, n;
n = 0;
for (i = 0; i < 2; i++) {
while (1) {
ret = umount2(root, MNT_DETACH);
if (ret < 0) {
if (n > 0 && errno == EINVAL)
ret = 0;
break;
}
n++;
}
if (ret == 0 || (ret < 0 && errno != EBUSY))
break;
sleep(1);
}
if (ret) {
logger(-1, errno, "Can't umount: %s", root);
ret = VZ_FS_CANTUMOUNT;
}
return ret;
}
/** Unmount CT.
*
* @param veid CT ID.
* @param root CT root.
* @return 0 on success.
*/
int fsumount(envid_t veid, const char *root)
{
int ret;
if (!(ret = real_umount(veid, root))) {
if (!quota_ctl(veid, QUOTA_STAT))
ret = quota_off(veid, 0);
}
return ret;
}
/** Mount CT and run mount action script if exists.
*
* @param h CT handler.
* @param veid CT ID.
* @param fs file system parameters.
* @param dq disk quota parameters.
* @param skip skip mount action scrips
* @return 0 on success.
*/
int vps_mount(vps_handler *h, envid_t veid, fs_param *fs, dq_param *dq,
skipFlags skip)
{
char buf[PATH_LEN];
int ret, i;
if (check_var(fs->root, "VE_ROOT is not set"))
return VZ_VE_ROOT_NOTSET;
if (check_var(fs->private, "VE_PRIVATE is not set"))
return VZ_VE_PRIVATE_NOTSET;
if (!stat_file(fs->private)) {
logger(-1, 0, "Container private area %s does not exist",
fs->private);
return VZ_FS_NOPRVT;
}
if (vps_is_mounted(fs->root)) {
logger(-1, 0, "Container is already mounted");
return 0;
}
/* Execute pre mount scripts */
if (!(skip & SKIP_ACTION_SCRIPT)) {
snprintf(buf, sizeof(buf), "%svps.%s", VPS_CONF_DIR,
PRE_MOUNT_PREFIX);
for (i = 0; i < 2; i++) {
if (run_pre_script(veid, buf)) {
logger(-1, 0, "Error executing mount script %s",
buf);
fsumount(veid, fs->root);
return VZ_ACTIONSCRIPT_ERROR;
}
snprintf(buf, sizeof(buf), "%s%d.%s", VPS_CONF_DIR,
veid, PRE_MOUNT_PREFIX);
}
}
if ((ret = fsmount(veid, fs, dq)))
return ret;
/* Execute per-CT & global mount scripts */
if (!(skip & SKIP_ACTION_SCRIPT)) {
snprintf(buf, sizeof(buf), "%svps.%s", VPS_CONF_DIR,
MOUNT_PREFIX);
for (i = 0; i < 2; i++) {
if (run_pre_script(veid, buf)) {
logger(-1, 0, "Error executing mount script %s",
buf);
fsumount(veid, fs->root);
return VZ_ACTIONSCRIPT_ERROR;
}
snprintf(buf, sizeof(buf), "%s%d.%s", VPS_CONF_DIR,
veid, MOUNT_PREFIX);
}
}
logger(0, 0, "Container is mounted");
return 0;
}
/** Unmount CT and run unmount action script if exists.
*
* @param h CT handler.
* @param veid CT ID.
* @param root CT root.
* @param skip skip unmount action scrips
* @return 0 on success.
*/
int vps_umount(vps_handler *h, envid_t veid, const char *root, skipFlags skip)
{
char buf[PATH_LEN];
int ret, i;
if (!vps_is_mounted(root)) {
logger(-1, 0, "CT is not mounted");
return VZ_FS_NOT_MOUNTED;
}
if (vps_is_run(h, veid)) {
logger(-1, 0, "Container is running -- stop it first");
return 0;
}
if (!(skip & SKIP_ACTION_SCRIPT)) {
snprintf(buf, sizeof(buf), "%s%d.%s", VPS_CONF_DIR,
veid, UMOUNT_PREFIX);
for (i = 0; i < 2; i++) {
if (run_pre_script(veid, buf)) {
logger(-1, 0, "Error executing umount script %s",
buf);
return VZ_ACTIONSCRIPT_ERROR;
}
snprintf(buf, sizeof(buf), "%svps.%s", VPS_CONF_DIR,
UMOUNT_PREFIX);
}
}
if (!(ret = fsumount(veid, root)))
logger(0, 0, "Container is unmounted");
if (!(skip & SKIP_ACTION_SCRIPT)) {
snprintf(buf, sizeof(buf), "%s%d.%s", VPS_CONF_DIR,
veid, POST_UMOUNT_PREFIX);
for (i = 0; i < 2; i++) {
if (run_pre_script(veid, buf)) {
logger(-1, 0, "Error executing umount script %s",
buf);
return VZ_ACTIONSCRIPT_ERROR;
}
snprintf(buf, sizeof(buf), "%svps.%s", VPS_CONF_DIR,
POST_UMOUNT_PREFIX);
}
}
return ret;
}
int vps_set_fs(fs_param *g_fs, fs_param *fs)
{
if (fs->noatime != YES)
return 0;
if (check_var(g_fs->root, "VE_ROOT is not set"))
return VZ_VE_ROOT_NOTSET;
if (check_var(g_fs->private, "VE_PRIVATE is not set"))
return VZ_VE_PRIVATE_NOTSET;
if (!vps_is_mounted(g_fs->root)) {
logger(-1, 0, "Container is not mounted");
return VZ_FS_NOT_MOUNTED;
}
g_fs->noatime = fs->noatime;
return vz_mount(g_fs, 1);
}