View of xos/fs/file_system_instance.c


XOS | Parent Directory | View | Download

/* Copyright (C) 2008  Emmanuel Varoquaux
 
   This file is part of XOS.
 
   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 3 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, see <http://www.gnu.org/licenses/>. */
 
#include "file_system_instance_struct.h"
#include "file_system_struct.h"
#include "device_struct.h"
 
#include <node.h>
#include <kmalloc.h>
#include <errno.h>
#include <consts.h>
#include <sprintf.h>
#include <string.h>
#include <assert.h>
#include <stddef.h>
 
static struct file_system_instance_struct *first = NULL;
static struct file_system_instance_struct *last = NULL;
 
static void insert(struct file_system_instance_struct *file_system_instance)
{
  file_system_instance->previous = last;
  file_system_instance->next = NULL;
  if (last)
    last->next = file_system_instance;
  else
    first = file_system_instance;
  last = file_system_instance;
}
 
static void remove(struct file_system_instance_struct *file_system_instance)
{
  if (file_system_instance->previous)
    file_system_instance->previous->next = file_system_instance->next;
  else
    first = file_system_instance->next;
  if (file_system_instance->next)
    file_system_instance->next->previous = file_system_instance->previous;
  else
    last = file_system_instance->previous;
}
 
int file_system_instance_init(struct file_system_instance_struct *file_system_instance, const struct file_system_struct *file_system, char *device_path, struct device_struct *device, const struct file_struct *mount_point)
{
  void *data;
  int rv;
 
  file_system_instance->file_system = file_system;
  file_system_instance->device_path = device_path;
  switch (file_system->type) {
  case FT_NONE:
    if ((rv = file_system->mount(NULL, &file_system_instance->data)) < 0)
      return rv;
    break;
  case FT_BLK:
    if (!device || device->type != FT_BLK)
      return -ENOTBLK;
    file_system_instance->device = device;
    if (device->count) {
      if (device->file_system != file_system)
        return -EBUSY;
    }
    else {
      if ((rv = file_system->mount(device, &data)) < 0)
        return rv;
      device->file_system = file_system;
      device->data = data;
    }
    device->count++;
    file_system_instance->data = device->data;
    break;
  }
  file_system_instance->count = 0;
  file_system_instance->mount_point = mount_point;
  insert(file_system_instance);
  return 0;
}
 
void file_system_instance_destroy(struct file_system_instance_struct *file_system_instance)
{
  assert(file_system_instance->count == 0);
  remove(file_system_instance);
  switch (file_system_instance->file_system->type) {
  case FT_NONE:
    file_system_instance->file_system->umount(file_system_instance->data);
    break;
  case FT_BLK:
    file_system_instance->device->count--;
    if (!file_system_instance->device->count) {
      file_system_instance->file_system->umount(file_system_instance->device->data);
      file_system_instance->device->file_system = NULL;
      file_system_instance->device->data = NULL;
    }
    break;
  }
  if (file_system_instance->device_path)
    kfree(file_system_instance->device_path, strlen(file_system_instance->device_path) + 1);
}
 
void file_system_instance_hold(struct file_system_instance_struct *file_system_instance)
{
  file_system_instance->count++;
}
 
void file_system_instance_release(struct file_system_instance_struct *file_system_instance)
{
  assert(file_system_instance->count > 0);
  file_system_instance->count--;
}
 
int file_system_instance_is_busy(const struct file_system_instance_struct *file_system_instance)
{
  return file_system_instance->count > 1; /* ne pas compter la reference courante */
}
 
/* procfs */
 
int print_mounts(char *buf, unsigned int size)
{
  char *s;
  const struct file_system_instance_struct *fsi;
  char *path;
  unsigned int n;
  int rv;
 
  s = buf;
  for (fsi = first; fsi; fsi = fsi->next) {
    if ((rv = get_path(fsi->mount_point, &path) < 0))
      return rv;
    n = snprintf(s, size, "%s %s %s\n", fsi->device_path ? : "none", path, fsi->file_system->name);
    s += n;
    size = size > n ? size - n : 0;
    kfree(path, strlen(path) + 1);
  }
  return s - buf;
}