提交 67435319 编写于 作者: E Evgeniy Polyakov 提交者: Greg Kroah-Hartman

staging: pohmelfs: remove drivers/staging/pohmelfs

New pohmelfs is coming, and it is time to remove deadly old design
https://lkml.org/lkml/2012/2/8/293Signed-off-by: NEvgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 203209ef
...@@ -60,8 +60,6 @@ source "drivers/staging/rts5139/Kconfig" ...@@ -60,8 +60,6 @@ source "drivers/staging/rts5139/Kconfig"
source "drivers/staging/frontier/Kconfig" source "drivers/staging/frontier/Kconfig"
source "drivers/staging/pohmelfs/Kconfig"
source "drivers/staging/phison/Kconfig" source "drivers/staging/phison/Kconfig"
source "drivers/staging/line6/Kconfig" source "drivers/staging/line6/Kconfig"
......
...@@ -22,7 +22,6 @@ obj-$(CONFIG_R8712U) += rtl8712/ ...@@ -22,7 +22,6 @@ obj-$(CONFIG_R8712U) += rtl8712/
obj-$(CONFIG_RTS_PSTOR) += rts_pstor/ obj-$(CONFIG_RTS_PSTOR) += rts_pstor/
obj-$(CONFIG_RTS5139) += rts5139/ obj-$(CONFIG_RTS5139) += rts5139/
obj-$(CONFIG_TRANZPORT) += frontier/ obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_POHMELFS) += pohmelfs/
obj-$(CONFIG_IDE_PHISON) += phison/ obj-$(CONFIG_IDE_PHISON) += phison/
obj-$(CONFIG_LINE6_USB) += line6/ obj-$(CONFIG_LINE6_USB) += line6/
obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/ obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
......
config POHMELFS
tristate "POHMELFS filesystem support"
depends on NET
select CONNECTOR
select CRYPTO
select CRYPTO_BLKCIPHER
select CRYPTO_HMAC
help
POHMELFS stands for Parallel Optimized Host Message Exchange Layered
File System. This is a network filesystem which supports coherent
caching of data and metadata on clients.
config POHMELFS_DEBUG
bool "POHMELFS debugging"
depends on POHMELFS
default n
help
Turns on excessive POHMELFS debugging facilities.
You usually do not want to slow things down noticeably and get really
lots of kernel messages in syslog.
obj-$(CONFIG_POHMELFS) += pohmelfs.o
pohmelfs-y := inode.o config.o dir.o net.o path_entry.o trans.o crypto.o lock.o mcache.o
/*
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
* 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.
*/
#include <linux/kernel.h>
#include <linux/connector.h>
#include <linux/crypto.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/in.h>
#include <linux/slab.h>
#include "netfs.h"
/*
* Global configuration list.
* Each client can be asked to get one of them.
*
* Allows to provide remote server address (ipv4/v6/whatever), port
* and so on via kernel connector.
*/
static struct cb_id pohmelfs_cn_id = {.idx = POHMELFS_CN_IDX, .val = POHMELFS_CN_VAL};
static LIST_HEAD(pohmelfs_config_list);
static DEFINE_MUTEX(pohmelfs_config_lock);
static inline int pohmelfs_config_eql(struct pohmelfs_ctl *sc, struct pohmelfs_ctl *ctl)
{
if (sc->idx == ctl->idx && sc->type == ctl->type &&
sc->proto == ctl->proto &&
sc->addrlen == ctl->addrlen &&
!memcmp(&sc->addr, &ctl->addr, ctl->addrlen))
return 1;
return 0;
}
static struct pohmelfs_config_group *pohmelfs_find_config_group(unsigned int idx)
{
struct pohmelfs_config_group *g, *group = NULL;
list_for_each_entry(g, &pohmelfs_config_list, group_entry) {
if (g->idx == idx) {
group = g;
break;
}
}
return group;
}
static struct pohmelfs_config_group *pohmelfs_find_create_config_group(unsigned int idx)
{
struct pohmelfs_config_group *g;
g = pohmelfs_find_config_group(idx);
if (g)
return g;
g = kzalloc(sizeof(struct pohmelfs_config_group), GFP_KERNEL);
if (!g)
return NULL;
INIT_LIST_HEAD(&g->config_list);
g->idx = idx;
g->num_entry = 0;
list_add_tail(&g->group_entry, &pohmelfs_config_list);
return g;
}
static inline void pohmelfs_insert_config_entry(struct pohmelfs_sb *psb, struct pohmelfs_config *dst)
{
struct pohmelfs_config *tmp;
INIT_LIST_HEAD(&dst->config_entry);
list_for_each_entry(tmp, &psb->state_list, config_entry) {
if (dst->state.ctl.prio > tmp->state.ctl.prio)
list_add_tail(&dst->config_entry, &tmp->config_entry);
}
if (list_empty(&dst->config_entry))
list_add_tail(&dst->config_entry, &psb->state_list);
}
static int pohmelfs_move_config_entry(struct pohmelfs_sb *psb,
struct pohmelfs_config *dst, struct pohmelfs_config *new)
{
if ((dst->state.ctl.prio == new->state.ctl.prio) &&
(dst->state.ctl.perm == new->state.ctl.perm))
return 0;
dprintk("%s: dst: prio: %d, perm: %x, new: prio: %d, perm: %d.\n",
__func__, dst->state.ctl.prio, dst->state.ctl.perm,
new->state.ctl.prio, new->state.ctl.perm);
dst->state.ctl.prio = new->state.ctl.prio;
dst->state.ctl.perm = new->state.ctl.perm;
list_del_init(&dst->config_entry);
pohmelfs_insert_config_entry(psb, dst);
return 0;
}
/*
* pohmelfs_copy_config() is used to copy new state configs from the
* config group (controlled by the netlink messages) into the superblock.
* This happens either at startup time where no transactions can access
* the list of the configs (and thus list of the network states), or at
* run-time, where it is protected by the psb->state_lock.
*/
int pohmelfs_copy_config(struct pohmelfs_sb *psb)
{
struct pohmelfs_config_group *g;
struct pohmelfs_config *c, *dst;
int err = -ENODEV;
mutex_lock(&pohmelfs_config_lock);
g = pohmelfs_find_config_group(psb->idx);
if (!g)
goto out_unlock;
/*
* Run over all entries in given config group and try to create and
* initialize those, which do not exist in superblock list.
* Skip all existing entries.
*/
list_for_each_entry(c, &g->config_list, config_entry) {
err = 0;
list_for_each_entry(dst, &psb->state_list, config_entry) {
if (pohmelfs_config_eql(&dst->state.ctl, &c->state.ctl)) {
err = pohmelfs_move_config_entry(psb, dst, c);
if (!err)
err = -EEXIST;
break;
}
}
if (err)
continue;
dst = kzalloc(sizeof(struct pohmelfs_config), GFP_KERNEL);
if (!dst) {
err = -ENOMEM;
break;
}
memcpy(&dst->state.ctl, &c->state.ctl, sizeof(struct pohmelfs_ctl));
pohmelfs_insert_config_entry(psb, dst);
err = pohmelfs_state_init_one(psb, dst);
if (err) {
list_del(&dst->config_entry);
kfree(dst);
}
err = 0;
}
out_unlock:
mutex_unlock(&pohmelfs_config_lock);
return err;
}
int pohmelfs_copy_crypto(struct pohmelfs_sb *psb)
{
struct pohmelfs_config_group *g;
int err = -ENOENT;
mutex_lock(&pohmelfs_config_lock);
g = pohmelfs_find_config_group(psb->idx);
if (!g)
goto err_out_exit;
if (g->hash_string) {
err = -ENOMEM;
psb->hash_string = kstrdup(g->hash_string, GFP_KERNEL);
if (!psb->hash_string)
goto err_out_exit;
psb->hash_strlen = g->hash_strlen;
}
if (g->cipher_string) {
psb->cipher_string = kstrdup(g->cipher_string, GFP_KERNEL);
if (!psb->cipher_string)
goto err_out_free_hash_string;
psb->cipher_strlen = g->cipher_strlen;
}
if (g->hash_keysize) {
psb->hash_key = kmemdup(g->hash_key, g->hash_keysize,
GFP_KERNEL);
if (!psb->hash_key)
goto err_out_free_cipher_string;
psb->hash_keysize = g->hash_keysize;
}
if (g->cipher_keysize) {
psb->cipher_key = kmemdup(g->cipher_key, g->cipher_keysize,
GFP_KERNEL);
if (!psb->cipher_key)
goto err_out_free_hash;
psb->cipher_keysize = g->cipher_keysize;
}
mutex_unlock(&pohmelfs_config_lock);
return 0;
err_out_free_hash:
kfree(psb->hash_key);
err_out_free_cipher_string:
kfree(psb->cipher_string);
err_out_free_hash_string:
kfree(psb->hash_string);
err_out_exit:
mutex_unlock(&pohmelfs_config_lock);
return err;
}
static int pohmelfs_send_reply(int err, int msg_num, int action, struct cn_msg *msg, struct pohmelfs_ctl *ctl)
{
struct pohmelfs_cn_ack *ack;
ack = kzalloc(sizeof(struct pohmelfs_cn_ack), GFP_KERNEL);
if (!ack)
return -ENOMEM;
memcpy(&ack->msg, msg, sizeof(struct cn_msg));
if (action == POHMELFS_CTLINFO_ACK)
memcpy(&ack->ctl, ctl, sizeof(struct pohmelfs_ctl));
ack->msg.len = sizeof(struct pohmelfs_cn_ack) - sizeof(struct cn_msg);
ack->msg.ack = msg->ack + 1;
ack->error = err;
ack->msg_num = msg_num;
cn_netlink_send(&ack->msg, 0, GFP_KERNEL);
kfree(ack);
return 0;
}
static int pohmelfs_cn_disp(struct cn_msg *msg)
{
struct pohmelfs_config_group *g;
struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data;
struct pohmelfs_config *c, *tmp;
int err = 0, i = 1;
if (msg->len != sizeof(struct pohmelfs_ctl))
return -EBADMSG;
mutex_lock(&pohmelfs_config_lock);
g = pohmelfs_find_config_group(ctl->idx);
if (!g) {
pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL);
goto out_unlock;
}
list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) {
struct pohmelfs_ctl *sc = &c->state.ctl;
if (pohmelfs_send_reply(err, g->num_entry - i, POHMELFS_CTLINFO_ACK, msg, sc)) {
err = -ENOMEM;
goto out_unlock;
}
i += 1;
}
out_unlock:
mutex_unlock(&pohmelfs_config_lock);
return err;
}
static int pohmelfs_cn_dump(struct cn_msg *msg)
{
struct pohmelfs_config_group *g;
struct pohmelfs_config *c, *tmp;
int err = 0, i = 1;
int total_msg = 0;
if (msg->len != sizeof(struct pohmelfs_ctl))
return -EBADMSG;
mutex_lock(&pohmelfs_config_lock);
list_for_each_entry(g, &pohmelfs_config_list, group_entry)
total_msg += g->num_entry;
if (total_msg == 0) {
if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL))
err = -ENOMEM;
goto out_unlock;
}
list_for_each_entry(g, &pohmelfs_config_list, group_entry) {
list_for_each_entry_safe(c, tmp, &g->config_list,
config_entry) {
struct pohmelfs_ctl *sc = &c->state.ctl;
if (pohmelfs_send_reply(err, total_msg - i,
POHMELFS_CTLINFO_ACK, msg,
sc)) {
err = -ENOMEM;
goto out_unlock;
}
i += 1;
}
}
out_unlock:
mutex_unlock(&pohmelfs_config_lock);
return err;
}
static int pohmelfs_cn_flush(struct cn_msg *msg)
{
struct pohmelfs_config_group *g;
struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data;
struct pohmelfs_config *c, *tmp;
int err = 0;
if (msg->len != sizeof(struct pohmelfs_ctl))
return -EBADMSG;
mutex_lock(&pohmelfs_config_lock);
if (ctl->idx != POHMELFS_NULL_IDX) {
g = pohmelfs_find_config_group(ctl->idx);
if (!g)
goto out_unlock;
list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) {
list_del(&c->config_entry);
g->num_entry--;
kfree(c);
}
} else {
list_for_each_entry(g, &pohmelfs_config_list, group_entry) {
list_for_each_entry_safe(c, tmp, &g->config_list,
config_entry) {
list_del(&c->config_entry);
g->num_entry--;
kfree(c);
}
}
}
out_unlock:
mutex_unlock(&pohmelfs_config_lock);
pohmelfs_cn_dump(msg);
return err;
}
static int pohmelfs_modify_config(struct pohmelfs_ctl *old, struct pohmelfs_ctl *new)
{
old->perm = new->perm;
old->prio = new->prio;
return 0;
}
static int pohmelfs_cn_ctl(struct cn_msg *msg, int action)
{
struct pohmelfs_config_group *g;
struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data;
struct pohmelfs_config *c, *tmp;
int err = 0;
if (msg->len != sizeof(struct pohmelfs_ctl))
return -EBADMSG;
mutex_lock(&pohmelfs_config_lock);
g = pohmelfs_find_create_config_group(ctl->idx);
if (!g) {
err = -ENOMEM;
goto out_unlock;
}
list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) {
struct pohmelfs_ctl *sc = &c->state.ctl;
if (pohmelfs_config_eql(sc, ctl)) {
if (action == POHMELFS_FLAGS_ADD) {
err = -EEXIST;
goto out_unlock;
} else if (action == POHMELFS_FLAGS_DEL) {
list_del(&c->config_entry);
g->num_entry--;
kfree(c);
goto out_unlock;
} else if (action == POHMELFS_FLAGS_MODIFY) {
err = pohmelfs_modify_config(sc, ctl);
goto out_unlock;
} else {
err = -EEXIST;
goto out_unlock;
}
}
}
if (action == POHMELFS_FLAGS_DEL) {
err = -EBADMSG;
goto out_unlock;
}
c = kzalloc(sizeof(struct pohmelfs_config), GFP_KERNEL);
if (!c) {
err = -ENOMEM;
goto out_unlock;
}
memcpy(&c->state.ctl, ctl, sizeof(struct pohmelfs_ctl));
g->num_entry++;
list_add_tail(&c->config_entry, &g->config_list);
out_unlock:
mutex_unlock(&pohmelfs_config_lock);
if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL))
err = -ENOMEM;
return err;
}
static int pohmelfs_crypto_hash_init(struct pohmelfs_config_group *g, struct pohmelfs_crypto *c)
{
char *algo = (char *)c->data;
u8 *key = (u8 *)(algo + c->strlen);
if (g->hash_string)
return -EEXIST;
g->hash_string = kstrdup(algo, GFP_KERNEL);
if (!g->hash_string)
return -ENOMEM;
g->hash_strlen = c->strlen;
g->hash_keysize = c->keysize;
g->hash_key = kmemdup(key, c->keysize, GFP_KERNEL);
if (!g->hash_key) {
kfree(g->hash_string);
return -ENOMEM;
}
return 0;
}
static int pohmelfs_crypto_cipher_init(struct pohmelfs_config_group *g, struct pohmelfs_crypto *c)
{
char *algo = (char *)c->data;
u8 *key = (u8 *)(algo + c->strlen);
if (g->cipher_string)
return -EEXIST;
g->cipher_string = kstrdup(algo, GFP_KERNEL);
if (!g->cipher_string)
return -ENOMEM;
g->cipher_strlen = c->strlen;
g->cipher_keysize = c->keysize;
g->cipher_key = kmemdup(key, c->keysize, GFP_KERNEL);
if (!g->cipher_key) {
kfree(g->cipher_string);
return -ENOMEM;
}
return 0;
}
static int pohmelfs_cn_crypto(struct cn_msg *msg)
{
struct pohmelfs_crypto *crypto = (struct pohmelfs_crypto *)msg->data;
struct pohmelfs_config_group *g;
int err = 0;
dprintk("%s: idx: %u, strlen: %u, type: %u, keysize: %u, algo: %s.\n",
__func__, crypto->idx, crypto->strlen, crypto->type,
crypto->keysize, (char *)crypto->data);
mutex_lock(&pohmelfs_config_lock);
g = pohmelfs_find_create_config_group(crypto->idx);
if (!g) {
err = -ENOMEM;
goto out_unlock;
}
switch (crypto->type) {
case POHMELFS_CRYPTO_HASH:
err = pohmelfs_crypto_hash_init(g, crypto);
break;
case POHMELFS_CRYPTO_CIPHER:
err = pohmelfs_crypto_cipher_init(g, crypto);
break;
default:
err = -ENOTSUPP;
break;
}
out_unlock:
mutex_unlock(&pohmelfs_config_lock);
if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL))
err = -ENOMEM;
return err;
}
static void pohmelfs_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
int err;
if (!cap_raised(current_cap(), CAP_SYS_ADMIN))
return;
switch (msg->flags) {
case POHMELFS_FLAGS_ADD:
case POHMELFS_FLAGS_DEL:
case POHMELFS_FLAGS_MODIFY:
err = pohmelfs_cn_ctl(msg, msg->flags);
break;
case POHMELFS_FLAGS_FLUSH:
err = pohmelfs_cn_flush(msg);
break;
case POHMELFS_FLAGS_SHOW:
err = pohmelfs_cn_disp(msg);
break;
case POHMELFS_FLAGS_DUMP:
err = pohmelfs_cn_dump(msg);
break;
case POHMELFS_FLAGS_CRYPTO:
err = pohmelfs_cn_crypto(msg);
break;
default:
err = -ENOSYS;
break;
}
}
int pohmelfs_config_check(struct pohmelfs_config *config, int idx)
{
struct pohmelfs_ctl *ctl = &config->state.ctl;
struct pohmelfs_config *tmp;
int err = -ENOENT;
struct pohmelfs_ctl *sc;
struct pohmelfs_config_group *g;
mutex_lock(&pohmelfs_config_lock);
g = pohmelfs_find_config_group(ctl->idx);
if (g) {
list_for_each_entry(tmp, &g->config_list, config_entry) {
sc = &tmp->state.ctl;
if (pohmelfs_config_eql(sc, ctl)) {
err = 0;
break;
}
}
}
mutex_unlock(&pohmelfs_config_lock);
return err;
}
int __init pohmelfs_config_init(void)
{
/* XXX remove (void *) cast when vanilla connector got synced */
return cn_add_callback(&pohmelfs_cn_id, "pohmelfs", (void *)pohmelfs_cn_callback);
}
void pohmelfs_config_exit(void)
{
struct pohmelfs_config *c, *tmp;
struct pohmelfs_config_group *g, *gtmp;
cn_del_callback(&pohmelfs_cn_id);
mutex_lock(&pohmelfs_config_lock);
list_for_each_entry_safe(g, gtmp, &pohmelfs_config_list, group_entry) {
list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) {
list_del(&c->config_entry);
kfree(c);
}
list_del(&g->group_entry);
kfree(g->hash_string);
kfree(g->cipher_string);
kfree(g);
}
mutex_unlock(&pohmelfs_config_lock);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
* 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.
*/
#include <linux/module.h>
#include <linux/backing-dev.h>
#include <linux/fs.h>
#include <linux/fsnotify.h>
#include <linux/mempool.h>
#include "netfs.h"
static int pohmelfs_send_lock_trans(struct pohmelfs_inode *pi,
u64 id, u64 start, u32 size, int type)
{
struct inode *inode = &pi->vfs_inode;
struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
struct netfs_trans *t;
struct netfs_cmd *cmd;
int path_len, err;
void *data;
struct netfs_lock *l;
int isize = (type & POHMELFS_LOCK_GRAB) ? 0 : sizeof(struct netfs_inode_info);
err = pohmelfs_path_length(pi);
if (err < 0)
goto err_out_exit;
path_len = err;
err = -ENOMEM;
t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize,
NETFS_TRANS_SINGLE_DST, 0);
if (!t)
goto err_out_exit;
cmd = netfs_trans_current(t);
data = cmd + 1;
err = pohmelfs_construct_path_string(pi, data, path_len);
if (err < 0)
goto err_out_free;
path_len = err;
l = data + path_len;
l->start = start;
l->size = size;
l->type = type;
l->ino = pi->ino;
cmd->cmd = NETFS_LOCK;
cmd->start = 0;
cmd->id = id;
cmd->size = sizeof(struct netfs_lock) + path_len + isize;
cmd->ext = path_len;
cmd->csize = 0;
netfs_convert_cmd(cmd);
netfs_convert_lock(l);
if (isize) {
struct netfs_inode_info *info = (struct netfs_inode_info *)(l + 1);
info->mode = inode->i_mode;
info->nlink = inode->i_nlink;
info->uid = inode->i_uid;
info->gid = inode->i_gid;
info->blocks = inode->i_blocks;
info->rdev = inode->i_rdev;
info->size = inode->i_size;
info->version = inode->i_version;
netfs_convert_inode_info(info);
}
netfs_trans_update(cmd, t, path_len + sizeof(struct netfs_lock) + isize);
return netfs_trans_finish(t, psb);
err_out_free:
netfs_trans_free(t);
err_out_exit:
printk("%s: err: %d.\n", __func__, err);
return err;
}
int pohmelfs_data_lock(struct pohmelfs_inode *pi, u64 start, u32 size, int type)
{
struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb);
struct pohmelfs_mcache *m;
int err = -ENOMEM;
struct iattr iattr;
struct inode *inode = &pi->vfs_inode;
dprintk("%s: %p: ino: %llu, start: %llu, size: %u, "
"type: %d, locked as: %d, owned: %d.\n",
__func__, &pi->vfs_inode, pi->ino,
start, size, type, pi->lock_type,
!!test_bit(NETFS_INODE_OWNED, &pi->state));
if (!pohmelfs_need_lock(pi, type))
return 0;
m = pohmelfs_mcache_alloc(psb, start, size, NULL);
if (IS_ERR(m))
return PTR_ERR(m);
err = pohmelfs_send_lock_trans(pi, m->gen, start, size,
type | POHMELFS_LOCK_GRAB);
if (err)
goto err_out_put;
err = wait_for_completion_timeout(&m->complete, psb->mcache_timeout);
if (err)
err = m->err;
else
err = -ETIMEDOUT;
if (err) {
printk("%s: %p: ino: %llu, mgen: %llu, start: %llu, size: %u, err: %d.\n",
__func__, &pi->vfs_inode, pi->ino, m->gen, start, size, err);
}
if (err && (err != -ENOENT))
goto err_out_put;
if (!err) {
netfs_convert_inode_info(&m->info);
iattr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_SIZE | ATTR_ATIME;
iattr.ia_mode = m->info.mode;
iattr.ia_uid = m->info.uid;
iattr.ia_gid = m->info.gid;
iattr.ia_size = m->info.size;
iattr.ia_atime = CURRENT_TIME;
dprintk("%s: %p: ino: %llu, mgen: %llu, start: %llu, isize: %llu -> %llu.\n",
__func__, &pi->vfs_inode, pi->ino, m->gen, start, inode->i_size, m->info.size);
err = pohmelfs_setattr_raw(inode, &iattr);
if (!err) {
struct dentry *dentry = d_find_alias(inode);
if (dentry) {
fsnotify_change(dentry, iattr.ia_valid);
dput(dentry);
}
}
}
pi->lock_type = type;
set_bit(NETFS_INODE_OWNED, &pi->state);
pohmelfs_mcache_put(psb, m);
return 0;
err_out_put:
pohmelfs_mcache_put(psb, m);
return err;
}
int pohmelfs_data_unlock(struct pohmelfs_inode *pi, u64 start, u32 size, int type)
{
dprintk("%s: %p: ino: %llu, start: %llu, size: %u, type: %d.\n",
__func__, &pi->vfs_inode, pi->ino, start, size, type);
pi->lock_type = 0;
clear_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state);
clear_bit(NETFS_INODE_OWNED, &pi->state);
return pohmelfs_send_lock_trans(pi, pi->ino, start, size, type);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
* 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.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/ktime.h>
#include <linux/fs_struct.h>
#include <linux/pagemap.h>
#include <linux/writeback.h>
#include <linux/mount.h>
#include <linux/mm.h>
#include "netfs.h"
#define UNHASHED_OBSCURE_STRING_SIZE sizeof(" (deleted)")
/*
* Create path from root for given inode.
* Path is formed as set of stuctures, containing name of the object
* and its inode data (mode, permissions and so on).
*/
int pohmelfs_construct_path_string(struct pohmelfs_inode *pi, void *data, int len)
{
struct path path;
struct dentry *d;
char *ptr;
int err = 0, strlen, reduce = 0;
d = d_find_alias(&pi->vfs_inode);
if (!d) {
printk("%s: no alias, list_empty: %d.\n", __func__, list_empty(&pi->vfs_inode.i_dentry));
return -ENOENT;
}
spin_lock(&current->fs->lock);
path.mnt = mntget(current->fs->root.mnt);
spin_unlock(&current->fs->lock);
path.dentry = d;
if (!IS_ROOT(d) && d_unhashed(d))
reduce = 1;
ptr = d_path(&path, data, len);
if (IS_ERR(ptr)) {
err = PTR_ERR(ptr);
goto out;
}
if (reduce && len >= UNHASHED_OBSCURE_STRING_SIZE) {
char *end = data + len - UNHASHED_OBSCURE_STRING_SIZE;
*end = '\0';
}
strlen = len - (ptr - (char *)data);
memmove(data, ptr, strlen);
ptr = data;
err = strlen;
dprintk("%s: dname: '%s', len: %u, maxlen: %u, name: '%s', strlen: %d.\n",
__func__, d->d_name.name, d->d_name.len, len, ptr, strlen);
out:
dput(d);
mntput(path.mnt);
return err;
}
int pohmelfs_path_length(struct pohmelfs_inode *pi)
{
struct dentry *d, *root, *first;
int len;
unsigned seq;
first = d_find_alias(&pi->vfs_inode);
if (!first) {
dprintk("%s: ino: %llu, mode: %o.\n", __func__, pi->ino, pi->vfs_inode.i_mode);
return -ENOENT;
}
spin_lock(&current->fs->lock);
root = dget(current->fs->root.dentry);
spin_unlock(&current->fs->lock);
rename_retry:
len = 1; /* Root slash */
d = first;
seq = read_seqbegin(&rename_lock);
rcu_read_lock();
if (!IS_ROOT(d) && d_unhashed(d))
len += UNHASHED_OBSCURE_STRING_SIZE; /* Obscure " (deleted)" string */
while (d && d != root && !IS_ROOT(d)) {
len += d->d_name.len + 1; /* Plus slash */
d = d->d_parent;
}
rcu_read_unlock();
if (read_seqretry(&rename_lock, seq))
goto rename_retry;
dput(root);
dput(first);
return len + 1; /* Including zero-byte */
}
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册