Whamcloud - gitweb
Merge b_md to HEAD for 0.5.19 release.
[fs/lustre-release.git] / lustre / lib / simple.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lib/simple.c
5  *
6  * Copyright (C) 2002  Cluster File Systems, Inc.
7  *
8  * This code is issued under the GNU General Public License.
9  * See the file COPYING in this distribution
10  *
11  * by Peter Braam <braam@clusterfs.com>
12  * and Andreas Dilger <adilger@clusterfs.com>
13  */
14
15 #define EXPORT_SYMTAB
16
17 #include <linux/version.h>
18 #include <linux/fs.h>
19 #include <asm/unistd.h>
20
21 #define DEBUG_SUBSYSTEM S_FILTER
22
23 #include <linux/obd_support.h>
24 #include <linux/obd.h>
25 #include <linux/lustre_mds.h>
26 #include <linux/lustre_lib.h>
27 #include <linux/lustre_net.h>
28
29 #ifdef OBD_CTXT_DEBUG
30 /* Debugging check only needed during development */
31 #define ASSERT_CTXT_MAGIC(magic) LASSERT((magic) == OBD_RUN_CTXT_MAGIC)
32 #define ASSERT_NOT_KERNEL_CTXT(msg) LASSERT(!segment_eq(get_fs(), get_ds()))
33 #define ASSERT_KERNEL_CTXT(msg) LASSERT(segment_eq(get_fs(), get_ds()))
34 #else
35 #define ASSERT_CTXT_MAGIC(magic) do {} while(0)
36 #define ASSERT_NOT_KERNEL_CTXT(msg) do {} while(0)
37 #define ASSERT_KERNEL_CTXT(msg) do {} while(0)
38 #endif
39
40 /* push / pop to root of obd store */
41 void push_ctxt(struct obd_run_ctxt *save, struct obd_run_ctxt *new_ctx,
42                struct obd_ucred *uc)
43 {
44         //ASSERT_NOT_KERNEL_CTXT("already in kernel context!\n");
45         ASSERT_CTXT_MAGIC(new_ctx->magic);
46         OBD_SET_CTXT_MAGIC(save);
47
48         /*
49         CDEBUG(D_INFO, "== push %p->%p == cur fs %p pwd %p (%*s), pwdmnt %p\n",
50                save, current, current->fs, current->fs->pwd,
51                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
52                current->fs->pwdmnt);
53         */
54
55         save->fs = get_fs();
56         LASSERT(atomic_read(&current->fs->pwd->d_count));
57         LASSERT(atomic_read(&new_ctx->pwd->d_count));
58         save->pwd = dget(current->fs->pwd);
59         save->pwdmnt = mntget(current->fs->pwdmnt);
60
61         LASSERT(save->pwd);
62         LASSERT(save->pwdmnt);
63         LASSERT(new_ctx->pwd);
64         LASSERT(new_ctx->pwdmnt);
65
66         if (uc) {
67                 save->fsuid = current->fsuid;
68                 save->fsgid = current->fsgid;
69                 save->cap = current->cap_effective;
70
71                 current->fsuid = uc->ouc_fsuid;
72                 current->fsgid = uc->ouc_fsgid;
73                 current->cap_effective = uc->ouc_cap;
74         }
75         set_fs(new_ctx->fs);
76         set_fs_pwd(current->fs, new_ctx->pwdmnt, new_ctx->pwd);
77
78         /*
79         CDEBUG(D_INFO, "== push %p==%p == cur fs %p pwd %p (%*s), pwdmnt %p\n",
80                new_ctx, current, current->fs, current->fs->pwd,
81                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
82                current->fs->pwdmnt);
83         */
84 }
85
86 void pop_ctxt(struct obd_run_ctxt *saved, struct obd_run_ctxt *new_ctx,
87               struct obd_ucred *uc)
88 {
89         //printk("pc0");
90         ASSERT_CTXT_MAGIC(saved->magic);
91         //printk("pc1");
92         ASSERT_KERNEL_CTXT("popping non-kernel context!\n");
93
94         /*
95         CDEBUG(D_INFO, " == pop  %p==%p == cur %p pwd %p (%*s), pwdmnt %p\n",
96                new_ctx, current, current->fs, current->fs->pwd,
97                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
98                current->fs->pwdmnt);
99         */
100
101         LASSERT(current->fs->pwd == new_ctx->pwd);
102         LASSERT(current->fs->pwdmnt == new_ctx->pwdmnt);
103
104         //printk("pc2");
105         set_fs(saved->fs);
106         //printk("pc3\n");
107         set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
108         //printk("pc4");
109
110         dput(saved->pwd);
111         //printk("pc5");
112         mntput(saved->pwdmnt);
113         //printk("pc6\n");
114         if (uc) {
115                 current->fsuid = saved->fsuid;
116                 current->fsgid = saved->fsgid;
117                 current->cap_effective = saved->cap;
118         }
119
120         /*
121         CDEBUG(D_INFO, "== pop  %p->%p == cur fs %p pwd %p (%*s), pwdmnt %p\n",
122                saved, current, current->fs, current->fs->pwd,
123                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
124                current->fs->pwdmnt);
125         */
126 }
127
128 /* utility to make a file */
129 struct dentry *simple_mknod(struct dentry *dir, char *name, int mode)
130 {
131         struct dentry *dchild;
132         int err = 0;
133         ENTRY;
134
135         ASSERT_KERNEL_CTXT("kernel doing mknod outside kernel context\n");
136         CDEBUG(D_INODE, "creating file %*s\n", (int)strlen(name), name);
137
138         down(&dir->d_inode->i_sem);
139         dchild = lookup_one_len(name, dir, strlen(name));
140         if (IS_ERR(dchild))
141                 GOTO(out_up, dchild);
142
143         if (dchild->d_inode) {
144                 if ((dchild->d_inode->i_mode & S_IFMT) != S_IFREG)
145                         GOTO(out_err, err = -EEXIST);
146
147                 GOTO(out_up, dchild);
148         }
149
150         err = vfs_create(dir->d_inode, dchild, (mode & ~S_IFMT) | S_IFREG);
151         if (err)
152                 GOTO(out_err, err);
153
154         up(&dir->d_inode->i_sem);
155         RETURN(dchild);
156
157 out_err:
158         dput(dchild);
159         dchild = ERR_PTR(err);
160 out_up:
161         up(&dir->d_inode->i_sem);
162         return dchild;
163 }
164
165 /* utility to make a directory */
166 struct dentry *simple_mkdir(struct dentry *dir, char *name, int mode)
167 {
168         struct dentry *dchild;
169         int err = 0;
170         ENTRY;
171
172         ASSERT_KERNEL_CTXT("kernel doing mkdir outside kernel context\n");
173         CDEBUG(D_INODE, "creating directory %*s\n", (int)strlen(name), name);
174         down(&dir->d_inode->i_sem);
175         dchild = lookup_one_len(name, dir, strlen(name));
176         if (IS_ERR(dchild))
177                 GOTO(out_up, dchild);
178
179         if (dchild->d_inode) {
180                 if (!S_ISDIR(dchild->d_inode->i_mode))
181                         GOTO(out_err, err = -ENOTDIR);
182
183                 GOTO(out_up, dchild);
184         }
185
186         err = vfs_mkdir(dir->d_inode, dchild, mode);
187         if (err)
188                 GOTO(out_err, err);
189
190         up(&dir->d_inode->i_sem);
191         RETURN(dchild);
192
193 out_err:
194         dput(dchild);
195         dchild = ERR_PTR(err);
196 out_up:
197         up(&dir->d_inode->i_sem);
198         return dchild;
199 }
200
201 /*
202  * Read a file from within kernel context.  Prior to calling this
203  * function we should already have done a push_ctxt().
204  */
205 int lustre_fread(struct file *file, char *str, int len, loff_t *off)
206 {
207         ASSERT_KERNEL_CTXT("kernel doing read outside kernel context\n");
208         if (!file || !file->f_op || !file->f_op->read || !off)
209                 RETURN(-ENOSYS);
210
211         return file->f_op->read(file, str, len, off);
212 }
213
214 /*
215  * Write a file from within kernel context.  Prior to calling this
216  * function we should already have done a push_ctxt().
217  */
218 int lustre_fwrite(struct file *file, const char *str, int len, loff_t *off)
219 {
220         ENTRY;
221         ASSERT_KERNEL_CTXT("kernel doing write outside kernel context\n");
222         if (!file)
223                 RETURN(-ENOENT);
224         if (!file->f_op)
225                 RETURN(-ENOSYS);
226         if (!off)
227                 RETURN(-EINVAL);
228
229         if (!file->f_op->write)
230                 RETURN(-EROFS);
231
232         RETURN(file->f_op->write(file, str, len, off));
233 }
234
235 /*
236  * Sync a file from within kernel context.  Prior to calling this
237  * function we should already have done a push_ctxt().
238  */
239 int lustre_fsync(struct file *file)
240 {
241         ENTRY;
242         ASSERT_KERNEL_CTXT("kernel doing sync outside kernel context\n");
243         if (!file || !file->f_op || !file->f_op->fsync)
244                 RETURN(-ENOSYS);
245
246         RETURN(file->f_op->fsync(file, file->f_dentry, 0));
247 }