Whamcloud - gitweb
LU-709 build: clean up i_mutex/i_private/quota_info macros
[fs/lustre-release.git] / lustre / lvfs / lvfs_linux.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Whamcloud, Inc.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/lvfs/lvfs_linux.c
37  *
38  * Author: Andreas Dilger <adilger@clusterfs.com>
39  */
40
41 #define DEBUG_SUBSYSTEM S_FILTER
42
43 #include <linux/version.h>
44 #include <linux/fs.h>
45 #include <asm/unistd.h>
46 #include <linux/slab.h>
47 #include <linux/pagemap.h>
48 #include <linux/quotaops.h>
49 #include <linux/version.h>
50 #include <libcfs/libcfs.h>
51 #include <lustre_fsfilt.h>
52 #include <obd.h>
53 #include <linux/module.h>
54 #include <linux/init.h>
55 #include <linux/lustre_compat25.h>
56 #include <lvfs.h>
57 #include "lvfs_internal.h"
58
59 #include <obd.h>
60 #include <lustre_lib.h>
61 #include <lustre_quota.h>
62
63 __u64 obd_max_pages = 0;
64 __u64 obd_max_alloc = 0;
65 struct lprocfs_stats *obd_memory = NULL;
66 EXPORT_SYMBOL(obd_memory);
67 cfs_spinlock_t obd_updatemax_lock = CFS_SPIN_LOCK_UNLOCKED;
68 /* refine later and change to seqlock or simlar from libcfs */
69
70 /* Debugging check only needed during development */
71 #ifdef OBD_CTXT_DEBUG
72 # define ASSERT_CTXT_MAGIC(magic) LASSERT((magic) == OBD_RUN_CTXT_MAGIC)
73 # define ASSERT_NOT_KERNEL_CTXT(msg) LASSERTF(!segment_eq(get_fs(), get_ds()),\
74                                               msg)
75 # define ASSERT_KERNEL_CTXT(msg) LASSERTF(segment_eq(get_fs(), get_ds()), msg)
76 #else
77 # define ASSERT_CTXT_MAGIC(magic) do {} while(0)
78 # define ASSERT_NOT_KERNEL_CTXT(msg) do {} while(0)
79 # define ASSERT_KERNEL_CTXT(msg) do {} while(0)
80 #endif
81
82 static void push_group_info(struct lvfs_run_ctxt *save,
83                             struct group_info *ginfo)
84 {
85         if (!ginfo) {
86                 save->ngroups = current_ngroups;
87                 current_ngroups = 0;
88         } else {
89                 struct cred *cred;
90                 task_lock(current);
91                 save->group_info = current_cred()->group_info;
92                 if ((cred = prepare_creds())) {
93                         cred->group_info = ginfo;
94                         commit_creds(cred);
95                 }
96                 task_unlock(current);
97         }
98 }
99
100 static void pop_group_info(struct lvfs_run_ctxt *save,
101                            struct group_info *ginfo)
102 {
103         if (!ginfo) {
104                 current_ngroups = save->ngroups;
105         } else {
106                 struct cred *cred;
107                 task_lock(current);
108                 if ((cred = prepare_creds())) {
109                         cred->group_info = save->group_info;
110                         commit_creds(cred);
111                 }
112                 task_unlock(current);
113         }
114 }
115
116 /* push / pop to root of obd store */
117 void push_ctxt(struct lvfs_run_ctxt *save, struct lvfs_run_ctxt *new_ctx,
118                struct lvfs_ucred *uc)
119 {
120         //ASSERT_NOT_KERNEL_CTXT("already in kernel context!\n");
121         ASSERT_CTXT_MAGIC(new_ctx->magic);
122         OBD_SET_CTXT_MAGIC(save);
123
124         save->fs = get_fs();
125         LASSERT(d_refcount(cfs_fs_pwd(current->fs)));
126         LASSERT(d_refcount(new_ctx->pwd));
127         save->pwd = dget(cfs_fs_pwd(current->fs));
128         save->pwdmnt = mntget(cfs_fs_mnt(current->fs));
129         save->luc.luc_umask = cfs_curproc_umask();
130         save->ngroups = current_cred()->group_info->ngroups;
131
132         LASSERT(save->pwd);
133         LASSERT(save->pwdmnt);
134         LASSERT(new_ctx->pwd);
135         LASSERT(new_ctx->pwdmnt);
136
137         if (uc) {
138                 struct cred *cred;
139                 save->luc.luc_uid = current_uid();
140                 save->luc.luc_gid = current_gid();
141                 save->luc.luc_fsuid = current_fsuid();
142                 save->luc.luc_fsgid = current_fsgid();
143                 save->luc.luc_cap = current_cap();
144
145                 if ((cred = prepare_creds())) {
146                         cred->uid = uc->luc_uid;
147                         cred->gid = uc->luc_gid;
148                         cred->fsuid = uc->luc_fsuid;
149                         cred->fsgid = uc->luc_fsgid;
150                         cred->cap_effective = uc->luc_cap;
151                         commit_creds(cred);
152                 }
153
154                 push_group_info(save,
155                                 uc->luc_ginfo ?:
156                                 uc->luc_identity ? uc->luc_identity->mi_ginfo :
157                                                    NULL);
158         }
159         current->fs->umask = 0; /* umask already applied on client */
160         set_fs(new_ctx->fs);
161         ll_set_fs_pwd(current->fs, new_ctx->pwdmnt, new_ctx->pwd);
162 }
163 EXPORT_SYMBOL(push_ctxt);
164
165 void pop_ctxt(struct lvfs_run_ctxt *saved, struct lvfs_run_ctxt *new_ctx,
166               struct lvfs_ucred *uc)
167 {
168         ASSERT_CTXT_MAGIC(saved->magic);
169         ASSERT_KERNEL_CTXT("popping non-kernel context!\n");
170
171         LASSERTF(cfs_fs_pwd(current->fs) == new_ctx->pwd, "%p != %p\n",
172                  cfs_fs_pwd(current->fs), new_ctx->pwd);
173         LASSERTF(cfs_fs_mnt(current->fs) == new_ctx->pwdmnt, "%p != %p\n",
174                  cfs_fs_mnt(current->fs), new_ctx->pwdmnt);
175
176         set_fs(saved->fs);
177         ll_set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
178
179         dput(saved->pwd);
180         mntput(saved->pwdmnt);
181         current->fs->umask = saved->luc.luc_umask;
182         if (uc) {
183                 struct cred *cred;
184                 if ((cred = prepare_creds())) {
185                         cred->uid = saved->luc.luc_uid;
186                         cred->gid = saved->luc.luc_gid;
187                         cred->fsuid = saved->luc.luc_fsuid;
188                         cred->fsgid = saved->luc.luc_fsgid;
189                         cred->cap_effective = saved->luc.luc_cap;
190                         commit_creds(cred);
191                 }
192
193                 pop_group_info(saved,
194                                uc->luc_ginfo ?:
195                                uc->luc_identity ? uc->luc_identity->mi_ginfo :
196                                                   NULL);
197         }
198 }
199 EXPORT_SYMBOL(pop_ctxt);
200
201 /* utility to make a file */
202 struct dentry *simple_mknod(struct dentry *dir, char *name, int mode, int fix)
203 {
204         struct dentry *dchild;
205         int err = 0;
206         ENTRY;
207
208         // ASSERT_KERNEL_CTXT("kernel doing mknod outside kernel context\n");
209         CDEBUG(D_INODE, "creating file %.*s\n", (int)strlen(name), name);
210
211         dchild = ll_lookup_one_len(name, dir, strlen(name));
212         if (IS_ERR(dchild))
213                 GOTO(out_up, dchild);
214
215         if (dchild->d_inode) {
216                 int old_mode = dchild->d_inode->i_mode;
217                 if (!S_ISREG(old_mode))
218                         GOTO(out_err, err = -EEXIST);
219
220                 /* Fixup file permissions if necessary */
221                 if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
222                         CWARN("fixing permissions on %s from %o to %o\n",
223                               name, old_mode, mode);
224                         dchild->d_inode->i_mode = (mode & S_IALLUGO) |
225                                                   (old_mode & ~S_IALLUGO);
226                         mark_inode_dirty(dchild->d_inode);
227                 }
228                 GOTO(out_up, dchild);
229         }
230
231         err = ll_vfs_create(dir->d_inode, dchild, (mode & ~S_IFMT) | S_IFREG,
232                             NULL);
233         if (err)
234                 GOTO(out_err, err);
235
236         RETURN(dchild);
237
238 out_err:
239         dput(dchild);
240         dchild = ERR_PTR(err);
241 out_up:
242         return dchild;
243 }
244 EXPORT_SYMBOL(simple_mknod);
245
246 /* utility to make a directory */
247 struct dentry *simple_mkdir(struct dentry *dir, struct vfsmount *mnt, 
248                             const char *name, int mode, int fix)
249 {
250         struct dentry *dchild;
251         int err = 0;
252         ENTRY;
253
254         // ASSERT_KERNEL_CTXT("kernel doing mkdir outside kernel context\n");
255         CDEBUG(D_INODE, "creating directory %.*s\n", (int)strlen(name), name);
256         dchild = ll_lookup_one_len(name, dir, strlen(name));
257         if (IS_ERR(dchild))
258                 GOTO(out_up, dchild);
259
260         if (dchild->d_inode) {
261                 int old_mode = dchild->d_inode->i_mode;
262                 if (!S_ISDIR(old_mode)) {
263                         CERROR("found %s (%lu/%u) is mode %o\n", name,
264                                dchild->d_inode->i_ino,
265                                dchild->d_inode->i_generation, old_mode);
266                         GOTO(out_err, err = -ENOTDIR);
267                 }
268
269                 /* Fixup directory permissions if necessary */
270                 if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
271                         CDEBUG(D_CONFIG,
272                                "fixing permissions on %s from %o to %o\n",
273                                name, old_mode, mode);
274                         dchild->d_inode->i_mode = (mode & S_IALLUGO) |
275                                                   (old_mode & ~S_IALLUGO);
276                         mark_inode_dirty(dchild->d_inode);
277                 }
278                 GOTO(out_up, dchild);
279         }
280
281         err = ll_vfs_mkdir(dir->d_inode, dchild, mnt, mode);
282         if (err)
283                 GOTO(out_err, err);
284
285         RETURN(dchild);
286
287 out_err:
288         dput(dchild);
289         dchild = ERR_PTR(err);
290 out_up:
291         return dchild;
292 }
293 EXPORT_SYMBOL(simple_mkdir);
294
295 /* utility to rename a file */
296 int lustre_rename(struct dentry *dir, struct vfsmount *mnt,
297                   char *oldname, char *newname)
298 {
299         struct dentry *dchild_old, *dchild_new;
300         int err = 0;
301         ENTRY;
302
303         ASSERT_KERNEL_CTXT("kernel doing rename outside kernel context\n");
304         CDEBUG(D_INODE, "renaming file %.*s to %.*s\n",
305                (int)strlen(oldname), oldname, (int)strlen(newname), newname);
306
307         dchild_old = ll_lookup_one_len(oldname, dir, strlen(oldname));
308         if (IS_ERR(dchild_old))
309                 RETURN(PTR_ERR(dchild_old));
310
311         if (!dchild_old->d_inode)
312                 GOTO(put_old, err = -ENOENT);
313
314         dchild_new = ll_lookup_one_len(newname, dir, strlen(newname));
315         if (IS_ERR(dchild_new))
316                 GOTO(put_old, err = PTR_ERR(dchild_new));
317
318         err = ll_vfs_rename(dir->d_inode, dchild_old, mnt,
319                             dir->d_inode, dchild_new, mnt);
320
321         dput(dchild_new);
322 put_old:
323         dput(dchild_old);
324         RETURN(err);
325 }
326 EXPORT_SYMBOL(lustre_rename);
327
328 /*
329  * Read a file from within kernel context.  Prior to calling this
330  * function we should already have done a push_ctxt().
331  */
332 int lustre_fread(struct file *file, void *buf, int len, loff_t *off)
333 {
334         ASSERT_KERNEL_CTXT("kernel doing read outside kernel context\n");
335         if (!file || !file->f_op || !file->f_op->read || !off)
336                 RETURN(-ENOSYS);
337
338         return file->f_op->read(file, buf, len, off);
339 }
340 EXPORT_SYMBOL(lustre_fread);
341
342 /*
343  * Write a file from within kernel context.  Prior to calling this
344  * function we should already have done a push_ctxt().
345  */
346 int lustre_fwrite(struct file *file, const void *buf, int len, loff_t *off)
347 {
348         ENTRY;
349         ASSERT_KERNEL_CTXT("kernel doing write outside kernel context\n");
350         if (!file)
351                 RETURN(-ENOENT);
352         if (!file->f_op)
353                 RETURN(-ENOSYS);
354         if (!off)
355                 RETURN(-EINVAL);
356
357         if (!file->f_op->write)
358                 RETURN(-EROFS);
359
360         RETURN(file->f_op->write(file, buf, len, off));
361 }
362 EXPORT_SYMBOL(lustre_fwrite);
363
364 /*
365  * Sync a file from within kernel context.  Prior to calling this
366  * function we should already have done a push_ctxt().
367  */
368 int lustre_fsync(struct file *file)
369 {
370         ENTRY;
371         ASSERT_KERNEL_CTXT("kernel doing sync outside kernel context\n");
372         if (!file || !file->f_op || !file->f_op->fsync)
373                 RETURN(-ENOSYS);
374
375         RETURN(cfs_do_fsync(file, 0));
376 }
377 EXPORT_SYMBOL(lustre_fsync);
378
379 /* Note: dput(dchild) will be called if there is an error */
380 struct l_file *l_dentry_open(struct lvfs_run_ctxt *ctxt, struct l_dentry *de,
381                              int flags)
382 {
383         mntget(ctxt->pwdmnt);
384         return ll_dentry_open(de, ctxt->pwdmnt, flags, current_cred());
385 }
386 EXPORT_SYMBOL(l_dentry_open);
387
388 static int l_filldir(void *__buf, const char *name, int namlen, loff_t offset,
389                      u64 ino, unsigned int d_type)
390 {
391         struct l_linux_dirent *dirent;
392         struct l_readdir_callback *buf = (struct l_readdir_callback *)__buf;
393
394         dirent = buf->lrc_dirent;
395         if (dirent)
396                dirent->lld_off = offset;
397
398         OBD_ALLOC(dirent, sizeof(*dirent));
399
400         if (!dirent)
401                 return -ENOMEM;
402
403         cfs_list_add_tail(&dirent->lld_list, buf->lrc_list);
404
405         buf->lrc_dirent = dirent;
406         dirent->lld_ino = ino;
407         LASSERT(sizeof(dirent->lld_name) >= namlen + 1);
408         memcpy(dirent->lld_name, name, namlen);
409
410         return 0;
411 }
412
413 long l_readdir(struct file *file, cfs_list_t *dentry_list)
414 {
415         struct l_linux_dirent *lastdirent;
416         struct l_readdir_callback buf;
417         int error;
418
419         buf.lrc_dirent = NULL;
420         buf.lrc_list = dentry_list;
421
422         error = vfs_readdir(file, l_filldir, &buf);
423         if (error < 0)
424                 return error;
425
426         lastdirent = buf.lrc_dirent;
427         if (lastdirent)
428                 lastdirent->lld_off = file->f_pos;
429
430         return 0;
431 }
432 EXPORT_SYMBOL(l_readdir);
433
434 int l_notify_change(struct vfsmount *mnt, struct dentry *dchild,
435                     struct iattr *newattrs)
436 {
437         int rc;
438
439         mutex_lock(&dchild->d_inode->i_mutex);
440 #ifdef HAVE_SECURITY_PLUG
441         rc = notify_change(dchild, mnt, newattrs);
442 #else
443         rc = notify_change(dchild, newattrs);
444 #endif
445         mutex_unlock(&dchild->d_inode->i_mutex);
446         return rc;
447 }
448 EXPORT_SYMBOL(l_notify_change);
449
450 /* utility to truncate a file */
451 int simple_truncate(struct dentry *dir, struct vfsmount *mnt, 
452                  char *name, loff_t length)
453 {
454         struct dentry *dchild;
455         struct iattr newattrs;
456         int err = 0;
457         ENTRY;
458
459         CDEBUG(D_INODE, "truncating file %.*s to %lld\n", (int)strlen(name),
460                name, (long long)length);
461         dchild = ll_lookup_one_len(name, dir, strlen(name));
462         if (IS_ERR(dchild))
463                 GOTO(out, err = PTR_ERR(dchild));
464
465         if (dchild->d_inode) {
466                 int old_mode = dchild->d_inode->i_mode;
467                 if (S_ISDIR(old_mode)) {
468                         CERROR("found %s (%lu/%u) is mode %o\n", name,
469                                dchild->d_inode->i_ino,
470                                dchild->d_inode->i_generation, old_mode);
471                         GOTO(out_dput, err = -EISDIR);
472                 }
473
474                 newattrs.ia_size = length;
475                 newattrs.ia_valid = ATTR_SIZE;
476                 err = l_notify_change(mnt, dchild, &newattrs);
477         }
478         EXIT;
479 out_dput:
480         dput(dchild);
481 out:
482         return err;
483 }
484 EXPORT_SYMBOL(simple_truncate);
485
486 int __lvfs_set_rdonly(lvfs_sbdev_type dev, lvfs_sbdev_type jdev)
487 {
488 #ifdef HAVE_DEV_SET_RDONLY
489         if (jdev && (jdev != dev)) {
490                 CDEBUG(D_IOCTL | D_HA, "set journal dev %lx rdonly\n",
491                        (long)jdev);
492                 dev_set_rdonly(jdev);
493         }
494         CDEBUG(D_IOCTL | D_HA, "set dev %lx rdonly\n", (long)dev);
495         dev_set_rdonly(dev);
496
497         return 0;
498 #else
499         CERROR("DEV %lx CANNOT BE SET READONLY\n", (long)dev);
500
501         return -EOPNOTSUPP;
502 #endif
503 }
504 EXPORT_SYMBOL(__lvfs_set_rdonly);
505
506 int lvfs_check_rdonly(lvfs_sbdev_type dev)
507 {
508 #ifdef HAVE_DEV_SET_RDONLY
509         return dev_check_rdonly(dev);
510 #else
511         return 0;
512 #endif
513 }
514 EXPORT_SYMBOL(lvfs_check_rdonly);
515
516 int lvfs_check_io_health(struct obd_device *obd, struct file *file)
517 {
518         char *write_page = NULL;
519         loff_t offset = 0;
520         int rc = 0;
521         ENTRY;
522
523         OBD_ALLOC(write_page, CFS_PAGE_SIZE);
524         if (!write_page)
525                 RETURN(-ENOMEM);
526
527         rc = fsfilt_write_record(obd, file, write_page, CFS_PAGE_SIZE, &offset, 1);
528
529         OBD_FREE(write_page, CFS_PAGE_SIZE);
530
531         CDEBUG(D_INFO, "write 1 page synchronously for checking io rc %d\n",rc);
532         RETURN(rc);
533 }
534 EXPORT_SYMBOL(lvfs_check_io_health);
535
536 void obd_update_maxusage()
537 {
538         __u64 max1, max2;
539
540         max1 = obd_pages_sum();
541         max2 = obd_memory_sum();
542
543         cfs_spin_lock(&obd_updatemax_lock);
544         if (max1 > obd_max_pages)
545                 obd_max_pages = max1;
546         if (max2 > obd_max_alloc)
547                 obd_max_alloc = max2;
548         cfs_spin_unlock(&obd_updatemax_lock);
549
550 }
551 EXPORT_SYMBOL(obd_update_maxusage);
552
553 __u64 obd_memory_max(void)
554 {
555         __u64 ret;
556
557         cfs_spin_lock(&obd_updatemax_lock);
558         ret = obd_max_alloc;
559         cfs_spin_unlock(&obd_updatemax_lock);
560
561         return ret;
562 }
563 EXPORT_SYMBOL(obd_memory_max);
564
565 __u64 obd_pages_max(void)
566 {
567         __u64 ret;
568
569         cfs_spin_lock(&obd_updatemax_lock);
570         ret = obd_max_pages;
571         cfs_spin_unlock(&obd_updatemax_lock);
572
573         return ret;
574 }
575 EXPORT_SYMBOL(obd_pages_max);
576
577 #ifdef LPROCFS
578 __s64 lprocfs_read_helper(struct lprocfs_counter *lc,
579                           enum lprocfs_fields_flags field)
580 {
581         __s64 ret = 0;
582         int centry;
583
584         if (!lc)
585                 RETURN(0);
586         do {
587                 centry = cfs_atomic_read(&lc->lc_cntl.la_entry);
588
589                 switch (field) {
590                         case LPROCFS_FIELDS_FLAGS_CONFIG:
591                                 ret = lc->lc_config;
592                                 break;
593                         case LPROCFS_FIELDS_FLAGS_SUM:
594                                 ret = lc->lc_sum + lc->lc_sum_irq;
595                                 break;
596                         case LPROCFS_FIELDS_FLAGS_MIN:
597                                 ret = lc->lc_min;
598                                 break;
599                         case LPROCFS_FIELDS_FLAGS_MAX:
600                                 ret = lc->lc_max;
601                                 break;
602                         case LPROCFS_FIELDS_FLAGS_AVG:
603                                 ret = (lc->lc_max - lc->lc_min)/2;
604                                 break;
605                         case LPROCFS_FIELDS_FLAGS_SUMSQUARE:
606                                 ret = lc->lc_sumsquare;
607                                 break;
608                         case LPROCFS_FIELDS_FLAGS_COUNT:
609                                 ret = lc->lc_count;
610                                 break;
611                         default:
612                                 break;
613                 };
614         } while (centry != cfs_atomic_read(&lc->lc_cntl.la_entry) &&
615                  centry != cfs_atomic_read(&lc->lc_cntl.la_exit));
616
617         RETURN(ret);
618 }
619 EXPORT_SYMBOL(lprocfs_read_helper);
620 #endif /* LPROCFS */
621
622 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
623 MODULE_DESCRIPTION("Lustre VFS Filesystem Helper v0.1");
624 MODULE_LICENSE("GPL");