1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
5 * Lustre filesystem abstraction routines
7 * Copyright (C) 2004 Cluster File Systems, Inc.
9 * This file is part of Lustre, http://www.lustre.org.
11 * Lustre is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public
13 * License as published by the Free Software Foundation.
15 * Lustre is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Lustre; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 # define EXPORT_SYMTAB
28 #define DEBUG_SUBSYSTEM S_SM
30 #include <linux/kmod.h>
31 #include <linux/init.h>
33 #include <linux/slab.h>
34 #include <linux/obd_class.h>
35 #include <linux/obd_support.h>
36 #include <linux/lustre_lib.h>
37 #include <linux/lustre_idl.h>
38 #include <linux/lustre_fsfilt.h>
39 #include <linux/lustre_smfs.h>
40 #include "smfs_internal.h"
42 #define KML_BUF_REC_INIT(buffer, pbuf, len) \
44 pbuf = buffer + sizeof(int); \
48 #define KML_BUF_REC_END(buffer, length, pbuf) \
51 memcpy(buffer, &len, sizeof(len)); \
52 length += sizeof(int); \
53 pbuf = buffer + length; \
56 static smfs_pack_rec_func smfs_get_rec_pack_type(struct super_block *sb)
59 struct smfs_super_info *smsi = S2SMI(sb);
61 idx = GET_REC_PACK_TYPE_INDEX(smsi->smsi_flags);
62 return smsi->smsi_pack_rec[idx];
65 static int smfs_post_kml_rec(struct inode *dir, void *de, void *data1,
68 static int smfs_rec_post_hook(struct inode *inode, void *dentry,
69 void *data1, void *data2, int op, void *handle)
74 if (smfs_do_rec(inode))
75 rc = smfs_post_kml_rec(inode, dentry, data1, data2, op);
80 #define KML_HOOK "kml_hook"
82 int smfs_rec_init(struct super_block *sb)
85 struct smfs_super_info *smfs_info = S2SMI(sb);
86 struct smfs_hook_ops *rec_hops = NULL;
89 SMFS_SET_REC(smfs_info);
91 rc = ost_rec_pack_init(smfs_info);
95 rc = mds_rec_pack_init(smfs_info);
99 rec_hops = smfs_alloc_hook_ops(KML_HOOK, NULL, smfs_rec_post_hook);
103 rc = smfs_register_hook_ops(smfs_info, rec_hops);
104 if (rc && rec_hops) {
105 smfs_unregister_hook_ops(smfs_info, rec_hops->smh_name);
106 smfs_free_hook_ops(rec_hops);
111 int smfs_rec_cleanup(struct smfs_super_info *smfs_info)
113 struct smfs_hook_ops *rec_hops;
117 rec_hops = smfs_unregister_hook_ops(smfs_info, KML_HOOK);
118 smfs_free_hook_ops(rec_hops);
119 SMFS_CLEAN_REC(smfs_info);
125 copy_inode_attr(struct iattr *iattr, struct inode *inode)
127 iattr->ia_mode = inode->i_mode;
128 iattr->ia_uid = inode->i_uid;
129 iattr->ia_gid = inode->i_gid;
130 iattr->ia_atime = inode->i_atime;
131 iattr->ia_ctime = inode->i_ctime;
132 iattr->ia_mtime = inode->i_mtime;
133 iattr->ia_size = inode->i_size;
136 static inline int unpack_rec_data(char **p_buffer, int *size,
137 char *in_data, char *args_data)
144 args_len = strlen(args_data);
146 *size = *((int*)(in_data));
147 rc = *size + sizeof(int);
149 OBD_ALLOC(*p_buffer, *size + args_len + 1);
153 /* first copy reint dir. */
155 memcpy(*p_buffer, args_data, args_len);
157 /* then copy the node name. */
158 memcpy(*p_buffer + args_len,
159 (in_data + sizeof(int)), *size);
166 int smfs_rec_unpack(struct smfs_proc_args *args, char *record,
167 char **pbuf, int *opcode)
169 int offset = *(int *)(record);
170 char *tmp = record + offset + sizeof(int);
172 *opcode = *(int *)tmp;
173 *pbuf = tmp + sizeof(*opcode);
176 EXPORT_SYMBOL(smfs_rec_unpack);
178 int smfs_start_rec(struct super_block *sb, struct vfsmount *mnt)
180 struct dentry *dentry;
181 struct lvfs_run_ctxt saved;
185 if (SMFS_INIT_REC(S2SMI(sb)) ||
186 (!SMFS_DO_REC(S2SMI(sb)) && !SMFS_CACHE_HOOK(S2SMI(sb))))
189 rc = smfs_llog_setup(sb, mnt);
192 push_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
193 dentry = simple_mkdir(current->fs->pwd, "DELETE", 0777, 1);
194 if (IS_ERR(dentry)) {
195 rc = PTR_ERR(dentry);
196 CERROR("cannot create DELETE directory: rc = %d\n", rc);
197 GOTO(err_exit, rc = -EINVAL);
199 S2SMI(sb)->smsi_delete_dir = dentry;
202 SMFS_SET_INIT_REC(S2SMI(sb));
204 pop_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
207 if (S2SMI(sb)->smsi_ctxt)
208 OBD_FREE(S2SMI(sb)->smsi_ctxt, sizeof(struct lvfs_run_ctxt));
211 EXPORT_SYMBOL(smfs_start_rec);
213 int smfs_post_setup(struct super_block *sb, struct vfsmount *mnt)
215 struct lvfs_run_ctxt *current_ctxt = NULL;
216 struct smfs_super_info *smb = S2SMI(sb);
219 OBD_ALLOC(current_ctxt, sizeof(*current_ctxt));
222 OBD_SET_CTXT_MAGIC(current_ctxt);
224 current_ctxt->pwdmnt = mnt;
225 current_ctxt->pwd = mnt->mnt_root;
226 current_ctxt->fs = get_ds();
227 smb->smsi_ctxt = current_ctxt;
231 EXPORT_SYMBOL(smfs_post_setup);
233 int smfs_post_cleanup(struct super_block *sb)
235 struct smfs_super_info *smb = S2SMI(sb);
239 OBD_FREE(S2SMI(sb)->smsi_ctxt, sizeof(struct lvfs_run_ctxt));
242 EXPORT_SYMBOL(smfs_post_cleanup);
244 int smfs_stop_rec(struct super_block *sb)
249 if (!SMFS_INIT_REC(S2SMI(sb)) ||
250 (!SMFS_DO_REC(S2SMI(sb)) && !SMFS_CACHE_HOOK(S2SMI(sb))))
253 rc = smfs_llog_cleanup(sb);
255 SMFS_CLEAN_INIT_REC(S2SMI(sb));
257 if (S2SMI(sb)->smsi_delete_dir) {
258 l_dput(S2SMI(sb)->smsi_delete_dir);
259 S2SMI(sb)->smsi_delete_dir = NULL;
263 EXPORT_SYMBOL(smfs_stop_rec);
265 int smfs_write_extents(struct inode *dir, struct dentry *dentry,
266 unsigned long from, unsigned long num)
268 return smfs_post_rec_write(dir, dentry, &from, &num);
270 EXPORT_SYMBOL(smfs_write_extents);
272 int smfs_rec_setattr(struct inode *dir, struct dentry *dentry,
275 return smfs_post_rec_setattr(dir, dentry, attr, NULL);
277 EXPORT_SYMBOL(smfs_rec_setattr);
279 int smfs_rec_md(struct inode *inode, void *lmm, int lmm_size,
282 char *set_lmm = NULL;
286 if (!SMFS_DO_REC(S2SMI(inode->i_sb)))
290 int size = lmm_size + sizeof(lmm_size) +
293 OBD_ALLOC(set_lmm, size);
297 memcpy(set_lmm, &lmm_size, sizeof(lmm_size));
298 memcpy(set_lmm + sizeof(lmm_size), &type, sizeof(type));
299 memcpy(set_lmm + sizeof(lmm_size) + sizeof(type), lmm, lmm_size);
301 rc = smfs_post_rec_setattr(inode, NULL, NULL, set_lmm);
303 CERROR("Error: Record md for inode %lu rc = %d\n",
306 OBD_FREE(set_lmm, size);
310 EXPORT_SYMBOL(smfs_rec_md);
312 int smfs_rec_precreate(struct dentry *dentry, int *num, struct obdo *oa)
314 return smfs_post_rec_create(dentry->d_inode, dentry, num, oa);
316 EXPORT_SYMBOL(smfs_rec_precreate);
318 int smfs_process_rec(struct super_block *sb,
319 int count, char *dir, int flags)
321 struct llog_ctxt *ctxt;
322 struct llog_handle *loghandle;
323 struct smfs_proc_args args;
327 if (!SMFS_INIT_REC(S2SMI(sb))) {
328 CWARN("Did not start up rec server \n");
332 memset(&args, 0, sizeof(struct smfs_proc_args));
334 args.sr_count = count;
336 args.sr_flags = flags ;
337 ctxt = S2SMI(sb)->smsi_rec_log;
338 loghandle = ctxt->loc_handle;
341 if (SMFS_DO_REINT_REC(flags)) {
342 struct llog_gen_rec *lgr;
344 /* for reint rec, we need insert a gen rec to identify
345 * the end of the rec.*/
346 OBD_ALLOC(lgr, sizeof(*lgr));
349 lgr->lgr_hdr.lrh_len = lgr->lgr_tail.lrt_len = sizeof(*lgr);
350 lgr->lgr_hdr.lrh_type = LLOG_GEN_REC;
351 lgr->lgr_gen = ctxt->loc_gen;
352 rc = llog_add(ctxt, &lgr->lgr_hdr, NULL, NULL, 1,
354 OBD_FREE(lgr, sizeof(*lgr));
359 SET_REC_COUNT_FLAGS(args.sr_flags, SMFS_REC_ALL);
362 if (SMFS_DO_REINT_REC(flags))
363 rc = llog_cat_process(loghandle, ctxt->llog_proc_cb,
366 rc = llog_cat_reverse_process(loghandle,
369 if (rc == LLOG_PROC_BREAK)
375 /*smfs_path is gotten from intermezzo*/
376 static char* smfs_path(struct dentry *dentry, struct dentry *root, char *buffer,
379 char * end = buffer + buflen;
380 char * name = buffer;
381 char * buf_end = buffer + buflen;
391 struct dentry * parent;
396 parent = dentry->d_parent;
397 if (dentry == parent)
399 namelen = dentry->d_name.len;
400 buflen -= namelen + 1;
404 memcpy(end, dentry->d_name.name, namelen);
410 while (end != buf_end)
416 static int smfs_log_path(struct super_block *sb,
417 struct dentry *dentry,
421 struct dentry *root=sb->s_root;
422 char *p_name = buffer + sizeof(int);
428 name = smfs_path(dentry, root, p_name, buffer_len - sizeof(int));
429 namelen = cpu_to_le32(strlen(p_name));
430 memcpy(buffer, &namelen, sizeof(int));
432 namelen += sizeof(int);
436 static inline int log_it(char *buffer, void *data, int length)
438 memcpy(buffer, &length, sizeof(int));
439 memcpy(buffer + sizeof(int), data, length);
440 return (sizeof(int) + length);
443 static int smfs_pack_rec (char *buffer, struct dentry *dentry,
444 struct inode *dir, void *data1,
447 smfs_pack_rec_func pack_func;
449 pack_func = smfs_get_rec_pack_type(dir->i_sb);
452 return pack_func(buffer, dentry, dir, data1, data2, op);
455 int smfs_post_rec_create(struct inode *dir, struct dentry *dentry,
456 void *data1, void *data2)
458 struct smfs_super_info *sinfo;
459 char *buffer = NULL, *pbuf;
460 int rc = 0, length = 0, buf_len = 0;
463 sinfo = S2SMI(dentry->d_inode->i_sb);
467 OBD_ALLOC(buffer, PAGE_SIZE);
469 GOTO(exit, rc = -ENOMEM);
472 KML_BUF_REC_INIT(buffer, pbuf, buf_len);
473 rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
477 KML_BUF_REC_END(buffer, length, pbuf);
479 rc = smfs_pack_rec(pbuf, dentry, dir,
480 data1, data2, REINT_CREATE);
485 rc = smfs_llog_add_rec(sinfo, (void*)buffer, length);
488 OBD_FREE(buffer, PAGE_SIZE);
493 static int smfs_post_rec_link(struct inode *dir, struct dentry *dentry,
494 void *data1, void *data2)
496 struct dentry *new_dentry = (struct dentry *)data1;
497 int rc = 0, length = 0, buf_len = 0;
498 char *buffer = NULL, *pbuf = NULL;
499 struct smfs_super_info *sinfo;
502 sinfo = S2SMI(dir->i_sb);
505 OBD_ALLOC(buffer, PAGE_SIZE);
507 GOTO(exit, rc = -ENOMEM);
510 KML_BUF_REC_INIT(buffer, pbuf, buf_len);
512 rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
517 KML_BUF_REC_END(buffer, length, pbuf);
519 rc = smfs_pack_rec(pbuf, dentry, dir, dentry,
520 new_dentry, REINT_LINK);
525 rc = smfs_llog_add_rec(sinfo, (void *)buffer, length);
528 OBD_FREE(buffer, PAGE_SIZE);
533 static int smfs_post_rec_unlink(struct inode *dir, struct dentry *dentry,
534 void *data1, void *data2)
536 struct smfs_super_info *sinfo;
537 int mode = *((int*)data1);
538 char *buffer = NULL, *pbuf = NULL;
539 int length = 0, rc = 0, buf_len = 0;
542 sinfo = S2SMI(dentry->d_inode->i_sb);
546 OBD_ALLOC(buffer, PAGE_SIZE);
548 GOTO(exit, rc = -ENOMEM);
551 KML_BUF_REC_INIT(buffer, pbuf, buf_len);
552 rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
557 KML_BUF_REC_END(buffer, length, pbuf);
558 rc = smfs_pack_rec(pbuf, dentry, dir,
559 &mode, NULL, REINT_UNLINK);
565 rc = smfs_llog_add_rec(sinfo, (void*)buffer, length);
568 OBD_FREE(buffer, PAGE_SIZE);
573 static int smfs_post_rec_rename(struct inode *dir, struct dentry *dentry,
574 void *data1, void *data2)
576 struct smfs_super_info *sinfo;
577 struct inode *new_dir = (struct inode *)data1;
578 struct dentry *new_dentry = (struct dentry *)data2;
579 char *buffer = NULL, *pbuf = NULL;
580 int rc = 0, length = 0, buf_len = 0;
583 sinfo = S2SMI(dir->i_sb);
587 OBD_ALLOC(buffer, PAGE_SIZE);
589 GOTO(exit, rc = -ENOMEM);
592 KML_BUF_REC_INIT(buffer, pbuf, buf_len);
593 rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
601 /* record new_dentry path. */
602 rc = smfs_log_path(dir->i_sb, new_dentry, pbuf, buf_len);
607 KML_BUF_REC_END(buffer, length, pbuf);
609 rc = smfs_pack_rec(pbuf, dentry, dir,
610 new_dir, new_dentry, REINT_RENAME);
615 rc = smfs_llog_add_rec(sinfo, (void*)buffer, length);
618 OBD_FREE(buffer, PAGE_SIZE);
622 static int smfs_insert_extents_ea(struct inode *inode, size_t from, loff_t num)
624 struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
628 if (SMFS_INODE_OVER_WRITE(inode))
631 rc = fsfilt->fs_insert_extents_ea(inode, OFF2BLKS(from, inode),
632 SIZE2BLKS(num, inode));
636 static int smfs_remove_extents_ea(struct inode *inode, size_t from, loff_t num)
638 struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
642 rc = fsfilt->fs_remove_extents_ea(inode, OFF2BLKS(from, inode),
643 SIZE2BLKS(num, inode));
648 static int smfs_remove_all_extents_ea(struct inode *inode)
650 struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
654 rc = fsfilt->fs_remove_extents_ea(inode, 0, 0xffffffff);
657 static int smfs_init_extents_ea(struct inode *inode)
659 struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
663 rc = fsfilt->fs_init_extents_ea(inode);
667 static int smfs_set_dirty_flags(struct inode *inode, int flags)
669 struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
674 if (SMFS_INODE_OVER_WRITE(inode))
676 /*FIXME later, the blocks needed in journal here will be recalculated*/
677 handle = smfs_trans_start(inode, FSFILT_OP_SETATTR, NULL);
678 if (IS_ERR(handle)) {
679 CERROR("smfs_set_dirty_flag:no space for transaction\n");
682 if ((!SMFS_INODE_DIRTY_WRITE(inode) && (!SMFS_INODE_OVER_WRITE(inode))) ||
683 ((flags == SMFS_OVER_WRITE) && (SMFS_INODE_DIRTY_WRITE(inode)))) {
684 rc = fsfilt->fs_set_xattr(inode, handle, REINT_EXTENTS_FLAGS,
685 &flags, sizeof(int));
689 if (flags == SMFS_OVER_WRITE)
690 SMFS_SET_INODE_OVER_WRITE(inode);
692 SMFS_SET_INODE_DIRTY_WRITE(inode);
694 smfs_trans_commit(inode, handle, 0);
698 int smfs_post_rec_setattr(struct inode *inode, struct dentry *dentry,
699 void *data1, void *data2)
701 struct iattr *attr = (struct iattr *)data1;
702 int rc = 0, length = 0, buf_len = 0;
703 struct smfs_super_info *sinfo;
704 char *buffer = NULL, *pbuf;
707 sinfo = S2SMI(inode->i_sb);
711 OBD_ALLOC(buffer, PAGE_SIZE);
713 GOTO(exit, rc = -ENOMEM);
716 KML_BUF_REC_INIT(buffer, pbuf, buf_len);
717 rc = smfs_log_path(inode->i_sb, dentry, pbuf, buf_len);
722 KML_BUF_REC_END(buffer, length, pbuf);
724 rc = smfs_pack_rec(pbuf, dentry, inode,
725 data1, data2, REINT_SETATTR);
731 rc = smfs_llog_add_rec(sinfo, (void*)buffer, length);
733 if (attr && attr->ia_valid & ATTR_SIZE) {
734 smfs_remove_extents_ea(inode, attr->ia_size,
736 if (attr->ia_size == 0)
737 smfs_set_dirty_flags(inode, SMFS_OVER_WRITE);
739 smfs_set_dirty_flags(inode, SMFS_DIRTY_WRITE);
744 OBD_FREE(buffer, PAGE_SIZE);
748 static int all_blocks_present_ea(struct inode *inode)
755 int smfs_post_rec_write(struct inode *dir, struct dentry *dentry, void *data1,
758 struct smfs_super_info *sinfo;
759 char *buffer = NULL, *pbuf;
760 int rc = 0, length = 0, buf_len = 0;
763 if (!SMFS_INODE_OVER_WRITE(dentry->d_inode) &&
764 !SMFS_INODE_DIRTY_WRITE(dentry->d_inode)) {
765 sinfo = S2SMI(dentry->d_inode->i_sb);
769 OBD_ALLOC(buffer, PAGE_SIZE);
771 GOTO(exit, rc = -ENOMEM);
774 KML_BUF_REC_INIT(buffer, pbuf, buf_len);
775 rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
780 memcpy(buffer, &rc, sizeof(int));
781 length = rc + sizeof(int);
783 rc = smfs_pack_rec(pbuf, dentry, dir,
784 data1, data2, REINT_WRITE);
790 rc = smfs_llog_add_rec(sinfo, (void*)buffer, length);
793 rc = smfs_init_extents_ea(dentry->d_inode);
797 if (dentry->d_inode->i_size == 0) {
798 smfs_set_dirty_flags(dentry->d_inode, SMFS_OVER_WRITE);
801 loff_t off = *((loff_t*)data1);
802 size_t count = *((size_t*)data2);
804 rc = smfs_insert_extents_ea(dentry->d_inode, off, count);
807 if (all_blocks_present_ea(dentry->d_inode)){
808 smfs_set_dirty_flags(dentry->d_inode, SMFS_OVER_WRITE);
809 smfs_remove_all_extents_ea(dentry->d_inode);
811 smfs_set_dirty_flags(dentry->d_inode, SMFS_DIRTY_WRITE);
816 OBD_FREE(buffer, PAGE_SIZE);
820 typedef int (*post_kml_rec)(struct inode *dir, struct dentry *dentry,
821 void *data1, void *data2);
823 static post_kml_rec smfs_kml_post[HOOK_MAX + 1] = {
824 [HOOK_CREATE] smfs_post_rec_create,
826 [HOOK_LINK] smfs_post_rec_link,
827 [HOOK_UNLINK] smfs_post_rec_unlink,
828 [HOOK_SYMLINK] smfs_post_rec_create,
829 [HOOK_MKDIR] smfs_post_rec_create,
830 [HOOK_RMDIR] smfs_post_rec_unlink,
831 [HOOK_MKNOD] smfs_post_rec_create,
832 [HOOK_RENAME] smfs_post_rec_rename,
833 [HOOK_SETATTR] smfs_post_rec_setattr,
834 [HOOK_WRITE] smfs_post_rec_write,
837 static int smfs_post_kml_rec(struct inode *dir, void *de, void *data1,
840 if (smfs_kml_post[op]) {
841 struct dentry *dentry = (struct dentry *)de;
842 return smfs_kml_post[op](dir, dentry, data1, data2);