~ubuntu-branches/ubuntu/karmic/linux-mvl-dove/karmic-proposed

« back to all changes in this revision

Viewing changes to ubuntu/iscsitarget/volume.c

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Bader
  • Date: 2010-03-10 22:24:12 UTC
  • mto: (15.1.2 karmic-security)
  • mto: This revision was merged to the branch mainline in revision 18.
  • Revision ID: james.westby@ubuntu.com-20100310222412-k86m3r53jw0je7x1
Tags: upstream-2.6.31
ImportĀ upstreamĀ versionĀ 2.6.31

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Volume manager
3
 
 * (C) 2004 - 2005 FUJITA Tomonori <tomof@acm.org>
4
 
 * This code is licenced under the GPL.
5
 
 */
6
 
 
7
 
#include <linux/types.h>
8
 
#include <linux/parser.h>
9
 
 
10
 
#include "iscsi.h"
11
 
#include "iscsi_dbg.h"
12
 
#include "iotype.h"
13
 
 
14
 
struct iet_volume *volume_lookup(struct iscsi_target *target, u32 lun)
15
 
{
16
 
        struct iet_volume *volume;
17
 
 
18
 
        list_for_each_entry(volume, &target->volumes, list) {
19
 
                if (volume->lun == lun)
20
 
                        return volume;
21
 
        }
22
 
        return NULL;
23
 
}
24
 
 
25
 
enum {
26
 
        Opt_type,
27
 
        Opt_iomode,
28
 
        Opt_err,
29
 
};
30
 
 
31
 
static match_table_t tokens = {
32
 
        {Opt_type, "Type=%s"},
33
 
        {Opt_iomode, "IOMode=%s"},
34
 
        {Opt_err, NULL},
35
 
};
36
 
 
37
 
static int set_iotype(struct iet_volume *volume, char *params)
38
 
{
39
 
        int err = 0;
40
 
        substring_t args[MAX_OPT_ARGS];
41
 
        char *p, *argp = NULL, *buf = (char *) get_zeroed_page(GFP_USER);
42
 
 
43
 
        if (!buf)
44
 
                return -ENOMEM;
45
 
        strncpy(buf, params, PAGE_CACHE_SIZE);
46
 
 
47
 
        while ((p = strsep(&buf, ",")) != NULL) {
48
 
                int token;
49
 
 
50
 
                if (!*p)
51
 
                        continue;
52
 
                token = match_token(p, tokens, args);
53
 
                switch (token) {
54
 
                case Opt_type:
55
 
                        if (!(argp = match_strdup(&args[0])))
56
 
                                err = -ENOMEM;
57
 
                        if (argp && !(volume->iotype = get_iotype(argp)))
58
 
                                err = -ENOENT;
59
 
                        kfree(argp);
60
 
                        break;
61
 
                case Opt_iomode:
62
 
                        if (!(argp = match_strdup(&args[0])))
63
 
                                err = -ENOMEM;
64
 
                        if (argp && !strcmp(argp, "ro"))
65
 
                                SetLUReadonly(volume);
66
 
                        else if (argp && !strcmp(argp, "wb"))
67
 
                                SetLUWCache(volume);
68
 
                        kfree(argp);
69
 
                        break;
70
 
                default:
71
 
                        break;
72
 
                }
73
 
        }
74
 
 
75
 
        if (!err && !volume->iotype && !(volume->iotype = get_iotype("fileio"))) {
76
 
                eprintk("%s\n", "Cannot find fileio");
77
 
                err = -EINVAL;
78
 
        }
79
 
 
80
 
        free_page((unsigned long) buf);
81
 
 
82
 
        return err;
83
 
}
84
 
 
85
 
int volume_add(struct iscsi_target *target, struct volume_info *info)
86
 
{
87
 
        int ret;
88
 
        struct iet_volume *volume;
89
 
        char *args;
90
 
 
91
 
        volume = volume_lookup(target, info->lun);
92
 
        if (volume)
93
 
                return -EEXIST;
94
 
 
95
 
        if (info->lun > 0x3fff)
96
 
                return -EINVAL;
97
 
 
98
 
        volume = kzalloc(sizeof(*volume), GFP_KERNEL);
99
 
        if (!volume)
100
 
                return -ENOMEM;
101
 
 
102
 
        volume->target = target;
103
 
        volume->lun = info->lun;
104
 
 
105
 
        args = kzalloc(info->args_len + 1, GFP_KERNEL);
106
 
        if (!args) {
107
 
                ret = -ENOMEM;
108
 
                goto free_volume;
109
 
        }
110
 
 
111
 
        ret = copy_from_user(args, (void *)(unsigned long)info->args_ptr,
112
 
                             info->args_len);
113
 
        if (ret) {
114
 
                ret = -EFAULT;
115
 
                goto free_args;
116
 
        }
117
 
 
118
 
        ret = set_iotype(volume, args);
119
 
        if (ret < 0)
120
 
                goto free_args;
121
 
 
122
 
        ret = volume->iotype->attach(volume, args);
123
 
        if (ret < 0)
124
 
                goto free_args;
125
 
 
126
 
        INIT_LIST_HEAD(&volume->queue.wait_list);
127
 
        spin_lock_init(&volume->queue.queue_lock);
128
 
        spin_lock_init(&volume->reserve_lock);
129
 
 
130
 
        volume->l_state = IDEV_RUNNING;
131
 
        atomic_set(&volume->l_count, 0);
132
 
 
133
 
        list_add_tail(&volume->list, &target->volumes);
134
 
        atomic_inc(&target->nr_volumes);
135
 
 
136
 
        kfree(args);
137
 
 
138
 
        return 0;
139
 
free_args:
140
 
        kfree(args);
141
 
free_volume:
142
 
        put_iotype(volume->iotype);
143
 
        kfree(volume);
144
 
 
145
 
        return ret;
146
 
}
147
 
 
148
 
void iscsi_volume_destroy(struct iet_volume *volume)
149
 
{
150
 
        assert(volume->l_state == IDEV_DEL);
151
 
        assert(!atomic_read(&volume->l_count));
152
 
 
153
 
        volume->iotype->detach(volume);
154
 
        put_iotype(volume->iotype);
155
 
        list_del(&volume->list);
156
 
        kfree(volume);
157
 
}
158
 
 
159
 
int iscsi_volume_del(struct iscsi_target *target, struct volume_info *info)
160
 
{
161
 
        struct iet_volume *volume;
162
 
 
163
 
        eprintk("%x %x\n", target->tid, info->lun);
164
 
        if (!(volume = volume_lookup(target, info->lun)))
165
 
                return -ENOENT;
166
 
 
167
 
        volume->l_state = IDEV_DEL;
168
 
        atomic_dec(&target->nr_volumes);
169
 
        if (!atomic_read(&volume->l_count))
170
 
                iscsi_volume_destroy(volume);
171
 
 
172
 
        return 0;
173
 
}
174
 
 
175
 
struct iet_volume *volume_get(struct iscsi_target *target, u32 lun)
176
 
{
177
 
        struct iet_volume *volume;
178
 
 
179
 
        if ((volume = volume_lookup(target, lun))) {
180
 
                if (volume->l_state == IDEV_RUNNING)
181
 
                        atomic_inc(&volume->l_count);
182
 
                else
183
 
                        volume = NULL;
184
 
        }
185
 
        return volume;
186
 
}
187
 
 
188
 
void volume_put(struct iet_volume *volume)
189
 
{
190
 
        if (atomic_dec_and_test(&volume->l_count) && volume->l_state == IDEV_DEL)
191
 
                iscsi_volume_destroy(volume);
192
 
}
193
 
 
194
 
int volume_reserve(struct iet_volume *volume, u64 sid)
195
 
{
196
 
        if (!volume)
197
 
                return -ENOENT;
198
 
 
199
 
        spin_lock(&volume->reserve_lock);
200
 
        if (volume->reserve_sid && volume->reserve_sid != sid) {
201
 
                spin_unlock(&volume->reserve_lock);
202
 
                return -EBUSY;
203
 
        }
204
 
 
205
 
        volume->reserve_sid = sid;
206
 
        spin_unlock(&volume->reserve_lock);
207
 
 
208
 
        return 0;
209
 
}
210
 
 
211
 
int is_volume_reserved(struct iet_volume *volume, u64 sid)
212
 
{
213
 
        if (!volume || !volume->reserve_sid || volume->reserve_sid == sid)
214
 
                return 0;
215
 
 
216
 
        return -EBUSY;
217
 
}
218
 
 
219
 
int volume_release(struct iet_volume *volume, u64 sid, int force)
220
 
{
221
 
        if (force || volume->reserve_sid == sid)
222
 
                volume->reserve_sid = 0;
223
 
 
224
 
        return 0;
225
 
}
226
 
 
227
 
static void iet_volume_info_show(struct seq_file *seq, struct iscsi_target *target)
228
 
{
229
 
        struct iet_volume *volume;
230
 
 
231
 
        list_for_each_entry(volume, &target->volumes, list) {
232
 
                seq_printf(seq, "\tlun:%u state:%x iotype:%s",
233
 
                           volume->lun, volume->l_state, volume->iotype->name);
234
 
                if (LUReadonly(volume))
235
 
                        seq_printf(seq, " iomode:ro");
236
 
                else if (LUWCache(volume))
237
 
                        seq_printf(seq, " iomode:wb");
238
 
                else
239
 
                        seq_printf(seq, " iomode:wt");
240
 
 
241
 
                if (volume->iotype->show)
242
 
                        volume->iotype->show(volume, seq);
243
 
                else
244
 
                        seq_printf(seq, "\n");
245
 
        }
246
 
}
247
 
 
248
 
static int iet_volume_seq_open(struct inode *inode, struct file *file)
249
 
{
250
 
        int res;
251
 
        res = seq_open(file, &iet_seq_op);
252
 
        if (!res)
253
 
                ((struct seq_file *)file->private_data)->private =
254
 
                        iet_volume_info_show;
255
 
        return res;
256
 
}
257
 
 
258
 
struct file_operations volume_seq_fops = {
259
 
        .owner          = THIS_MODULE,
260
 
        .open           = iet_volume_seq_open,
261
 
        .read           = seq_read,
262
 
        .llseek         = seq_lseek,
263
 
        .release        = seq_release,
264
 
};