linux/drivers/staging/pohmelfs/lock.c
<<
>>
Prefs
   1/*
   2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
   3 * All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/backing-dev.h>
  18#include <linux/fs.h>
  19#include <linux/fsnotify.h>
  20#include <linux/slab.h>
  21#include <linux/mempool.h>
  22
  23#include "netfs.h"
  24
  25static int pohmelfs_send_lock_trans(struct pohmelfs_inode *pi,
  26                u64 id, u64 start, u32 size, int type)
  27{
  28        struct inode *inode = &pi->vfs_inode;
  29        struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
  30        struct netfs_trans *t;
  31        struct netfs_cmd *cmd;
  32        int path_len, err;
  33        void *data;
  34        struct netfs_lock *l;
  35        int isize = (type & POHMELFS_LOCK_GRAB) ? 0 : sizeof(struct netfs_inode_info);
  36
  37        err = pohmelfs_path_length(pi);
  38        if (err < 0)
  39                goto err_out_exit;
  40
  41        path_len = err;
  42
  43        err = -ENOMEM;
  44        t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize,
  45                        NETFS_TRANS_SINGLE_DST, 0);
  46        if (!t)
  47                goto err_out_exit;
  48
  49        cmd = netfs_trans_current(t);
  50        data = cmd + 1;
  51
  52        err = pohmelfs_construct_path_string(pi, data, path_len);
  53        if (err < 0)
  54                goto err_out_free;
  55        path_len = err;
  56
  57        l = data + path_len;
  58
  59        l->start = start;
  60        l->size = size;
  61        l->type = type;
  62        l->ino = pi->ino;
  63
  64        cmd->cmd = NETFS_LOCK;
  65        cmd->start = 0;
  66        cmd->id = id;
  67        cmd->size = sizeof(struct netfs_lock) + path_len + isize;
  68        cmd->ext = path_len;
  69        cmd->csize = 0;
  70
  71        netfs_convert_cmd(cmd);
  72        netfs_convert_lock(l);
  73
  74        if (isize) {
  75                struct netfs_inode_info *info = (struct netfs_inode_info *)(l + 1);
  76
  77                info->mode = inode->i_mode;
  78                info->nlink = inode->i_nlink;
  79                info->uid = inode->i_uid;
  80                info->gid = inode->i_gid;
  81                info->blocks = inode->i_blocks;
  82                info->rdev = inode->i_rdev;
  83                info->size = inode->i_size;
  84                info->version = inode->i_version;
  85
  86                netfs_convert_inode_info(info);
  87        }
  88
  89        netfs_trans_update(cmd, t, path_len + sizeof(struct netfs_lock) + isize);
  90
  91        return netfs_trans_finish(t, psb);
  92
  93err_out_free:
  94        netfs_trans_free(t);
  95err_out_exit:
  96        printk("%s: err: %d.\n", __func__, err);
  97        return err;
  98}
  99
 100int pohmelfs_data_lock(struct pohmelfs_inode *pi, u64 start, u32 size, int type)
 101{
 102        struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb);
 103        struct pohmelfs_mcache *m;
 104        int err = -ENOMEM;
 105        struct iattr iattr;
 106        struct inode *inode = &pi->vfs_inode;
 107
 108        dprintk("%s: %p: ino: %llu, start: %llu, size: %u, "
 109                        "type: %d, locked as: %d, owned: %d.\n",
 110                        __func__, &pi->vfs_inode, pi->ino,
 111                        start, size, type, pi->lock_type,
 112                        !!test_bit(NETFS_INODE_OWNED, &pi->state));
 113
 114        if (!pohmelfs_need_lock(pi, type))
 115                return 0;
 116
 117        m = pohmelfs_mcache_alloc(psb, start, size, NULL);
 118        if (IS_ERR(m))
 119                return PTR_ERR(m);
 120
 121        err = pohmelfs_send_lock_trans(pi, m->gen, start, size,
 122                        type | POHMELFS_LOCK_GRAB);
 123        if (err)
 124                goto err_out_put;
 125
 126        err = wait_for_completion_timeout(&m->complete, psb->mcache_timeout);
 127        if (err)
 128                err = m->err;
 129        else
 130                err = -ETIMEDOUT;
 131
 132        if (err) {
 133                printk("%s: %p: ino: %llu, mgen: %llu, start: %llu, size: %u, err: %d.\n",
 134                        __func__, &pi->vfs_inode, pi->ino, m->gen, start, size, err);
 135        }
 136
 137        if (err && (err != -ENOENT))
 138                goto err_out_put;
 139
 140        if (!err) {
 141                netfs_convert_inode_info(&m->info);
 142
 143                iattr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_SIZE | ATTR_ATIME;
 144                iattr.ia_mode = m->info.mode;
 145                iattr.ia_uid = m->info.uid;
 146                iattr.ia_gid = m->info.gid;
 147                iattr.ia_size = m->info.size;
 148                iattr.ia_atime = CURRENT_TIME;
 149
 150                dprintk("%s: %p: ino: %llu, mgen: %llu, start: %llu, isize: %llu -> %llu.\n",
 151                        __func__, &pi->vfs_inode, pi->ino, m->gen, start, inode->i_size, m->info.size);
 152
 153                err = pohmelfs_setattr_raw(inode, &iattr);
 154                if (!err) {
 155                        struct dentry *dentry = d_find_alias(inode);
 156                        if (dentry) {
 157                                fsnotify_change(dentry, iattr.ia_valid);
 158                                dput(dentry);
 159                        }
 160                }
 161        }
 162
 163        pi->lock_type = type;
 164        set_bit(NETFS_INODE_OWNED, &pi->state);
 165
 166        pohmelfs_mcache_put(psb, m);
 167
 168        return 0;
 169
 170err_out_put:
 171        pohmelfs_mcache_put(psb, m);
 172        return err;
 173}
 174
 175int pohmelfs_data_unlock(struct pohmelfs_inode *pi, u64 start, u32 size, int type)
 176{
 177        dprintk("%s: %p: ino: %llu, start: %llu, size: %u, type: %d.\n",
 178                        __func__, &pi->vfs_inode, pi->ino, start, size, type);
 179        pi->lock_type = 0;
 180        clear_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state);
 181        clear_bit(NETFS_INODE_OWNED, &pi->state);
 182        return pohmelfs_send_lock_trans(pi, pi->ino, start, size, type);
 183}
 184