📄 journal.c
字号:
/* * Intermezzo. (C) 1998 Peter J. Braam * * Support for journalling extended attributes * (C) 2001 Shirish H. Phatak, Tacit Networks, Inc. */#include <linux/types.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/time.h>#include <linux/errno.h>#include <linux/locks.h>#include <asm/segment.h>#include <asm/uaccess.h>#include <linux/string.h>#include <linux/smp_lock.h>#include <linux/intermezzo_fs.h>#include <linux/intermezzo_upcall.h>#include <linux/intermezzo_psdev.h>#include <linux/intermezzo_kml.h>static int presto_log(struct presto_file_set *fset, struct rec_info *rec, const char *buf, size_t size, const char *string1, int len1, const char *string2, int len2, const char *string3, int len3);/* * reserve record space and/or atomically request state of the log * rec will hold the location reserved record upon return * this reservation will be placed in the queue */ static void presto_reserve_record(struct presto_file_set *fset, struct presto_log_fd *fd, struct rec_info *rec, struct presto_reservation_data *rd){ int chunked_record = 0; ENTRY; write_lock(&fd->fd_lock); if ( rec->is_kml ) { int chunk = 1 << fset->fset_chunkbits; int chunk_mask = ~(chunk -1); loff_t boundary; boundary = (fd->fd_offset + chunk - 1) & chunk_mask; if ( fd->fd_offset + rec->size >= boundary ) { chunked_record = 1; fd->fd_offset = boundary; } } fd->fd_recno++; /* this move the fd_offset back after truncation */ if ( list_empty(&fd->fd_reservations) && !chunked_record) { fd->fd_offset = fd->fd_file->f_dentry->d_inode->i_size; } rec->offset = fd->fd_offset; rec->recno = fd->fd_recno; fd->fd_offset += rec->size; /* add the reservation data to the end of the list */ list_add(&rd->ri_list, fd->fd_reservations.prev); rd->ri_offset = rec->offset; rd->ri_size = rec->size; rd->ri_recno = rec->recno; write_unlock(&fd->fd_lock); EXIT;}static inline void presto_release_record(struct presto_log_fd *fd, struct presto_reservation_data *rd){ write_lock(&fd->fd_lock); list_del(&rd->ri_list); write_unlock(&fd->fd_lock);}static int presto_do_truncate(struct presto_file_set *fset, struct dentry *dentry, loff_t length, loff_t size_check){ struct inode *inode = dentry->d_inode; struct inode_operations *op; int error; struct iattr newattrs; ENTRY; /* Not pretty: "inode->i_size" shouldn't really be "loff_t". */ if ((off_t) length < 0) return -EINVAL; fs_down(&inode->i_sem); lock_kernel(); if (size_check != inode->i_size) { unlock_kernel(); fs_up(&inode->i_sem); EXIT; return -EALREADY; } newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; op = filter_c2cfiops(fset->fset_cache->cache_filter); if (op != NULL && op->setattr != NULL) error = op->setattr(dentry, &newattrs); else { inode_setattr(dentry->d_inode, &newattrs); /* Some filesystems, e.g. ext2 and older versions of ext3 legitimately do not have a <fs>_setattr method. -SHP */ /* printk ("Warning:: int presto_do_truncate(xxx), op->setattr == NULL"); error = -EOPNOTSUPP; */ error = 0; } unlock_kernel(); fs_up(&inode->i_sem); EXIT; return error;}void *presto_trans_start(struct presto_file_set *fset, struct inode *inode, int op){ ENTRY; if ( !fset->fset_cache->cache_filter->o_trops ) return NULL; EXIT; return fset->fset_cache->cache_filter->o_trops->tr_start (fset, inode, op);}void presto_trans_commit(struct presto_file_set *fset, void *handle){ ENTRY; if (!fset->fset_cache->cache_filter->o_trops ) return; EXIT; return fset->fset_cache->cache_filter->o_trops->tr_commit(fset, handle);}inline int presto_no_journal(struct presto_file_set *fset){ int minor = fset->fset_cache->cache_psdev->uc_minor; return upc_comms[minor].uc_no_journal;}#define size_round(x) (((x)+3) & ~0x3)#define BUFF_FREE(buf) PRESTO_FREE(buf, PAGE_SIZE)#define BUFF_ALLOC(newbuf, oldbuf) \ PRESTO_ALLOC(newbuf, char *, PAGE_SIZE); \ if ( !newbuf ) { \ if (oldbuf) \ BUFF_FREE(oldbuf); \ return -ENOMEM; \ }/* * "buflen" should be PAGE_SIZE or more. * Give relative path wrt to a fsetroot */char * presto_path(struct dentry *dentry, struct dentry *root, char *buffer, int buflen){ char * end = buffer+buflen; char * retval; *--end = '\0'; buflen--; if (dentry->d_parent != dentry && list_empty(&dentry->d_hash)) { buflen -= 10; end -= 10; memcpy(end, " (deleted)", 10); } /* Get '/' right */ retval = end-1; *retval = '/'; for (;;) { struct dentry * parent; int namelen; if (dentry == root) break; parent = dentry->d_parent; if (dentry == parent) break; namelen = dentry->d_name.len; buflen -= namelen + 1; if (buflen < 0) break; end -= namelen; memcpy(end, dentry->d_name.name, namelen); *--end = '/'; retval = end; dentry = parent; } return retval;}static inline char *logit(char *buf, const void *value, int size){ char *ptr = (char *)value; memcpy(buf, ptr, size); buf += size; return buf;}static inline char *journal_log_prefix_with_groups_and_ids(char *buf, int opcode, struct rec_info *rec, __u32 ngroups, gid_t *groups, __u32 fsuid, __u32 fsgid){ struct big_journal_prefix p; int i; p.len = cpu_to_le32(rec->size); p.version = PRESTO_KML_MAJOR_VERSION | PRESTO_KML_MINOR_VERSION; p.pid = cpu_to_le32(current->pid); p.uid = cpu_to_le32(current->uid); p.fsuid = cpu_to_le32(fsuid); p.fsgid = cpu_to_le32(fsgid); p.ngroups = cpu_to_le32(ngroups); p.opcode = cpu_to_le32(opcode); for (i=0 ; i < ngroups ; i++) p.groups[i] = cpu_to_le32((__u32) groups[i]); buf = logit(buf, &p, sizeof(struct journal_prefix) + sizeof(__u32) * ngroups); return buf;}static inline char *journal_log_prefix(char *buf, int opcode, struct rec_info *rec){ __u32 groups[NGROUPS_MAX]; int i; /* convert 16 bit gid's to 32 bit gid's */ for (i=0; i<current->ngroups; i++) groups[i] = (__u32) current->groups[i]; return journal_log_prefix_with_groups_and_ids(buf, opcode, rec, (__u32)current->ngroups, groups, (__u32)current->fsuid, (__u32)current->fsgid);}static inline char *journal_log_prefix_with_groups(char *buf, int opcode, struct rec_info *rec, __u32 ngroups, gid_t *groups){ return journal_log_prefix_with_groups_and_ids(buf, opcode, rec, ngroups, groups, (__u32)current->fsuid, (__u32)current->fsgid);}static inline char *log_version(char *buf, struct dentry *dentry){ struct presto_version version; presto_getversion(&version, dentry->d_inode); return logit(buf, &version, sizeof(version));}static inline char *journal_log_suffix(char *buf, char *log, struct presto_file_set *fset, struct dentry *dentry, struct rec_info *rec){ struct journal_suffix s; struct journal_prefix *p = (struct journal_prefix *)log;#if 0 /* XXX needs to be done after reservation, disable ths until version 1.2 */ if ( dentry ) { s.prevrec = cpu_to_le32(rec->offset - dentry->d_time); dentry->d_time = (unsigned long) rec->offset; } else { s.prevrec = -1; }#endif s.prevrec = 0; /* record number needs to be filled in after reservation s.recno = cpu_to_le32(rec->recno); */ s.time = cpu_to_le32(CURRENT_TIME); s.len = cpu_to_le32(p->len); return logit(buf, &s, sizeof(s));}int presto_close_journal_file(struct presto_file_set *fset){ int rc = 0; int rc2 = 0; int rc3 = 0; ENTRY; if ( fset->fset_kml.fd_file) { rc =filp_close(fset->fset_kml.fd_file, 0); fset->fset_kml.fd_file = NULL; } else { printk("hehehehe no filp\n"); } if ( rc ) { printk("presto: close files: kml filp won't close %d\n", rc); } if ( fset->fset_last_rcvd) { rc2 = filp_close(fset->fset_last_rcvd, 0); fset->fset_last_rcvd = NULL; } else { printk("hehehehe no filp\n"); } if ( rc2 ) { if ( !rc ) rc = rc2; printk("presto: close files: last_rcvd filp won't close %d\n", rc2); } if ( fset->fset_lml.fd_file) { rc3 = filp_close(fset->fset_lml.fd_file, 0); fset->fset_lml.fd_file = NULL; } else { printk("hehehehe no filp\n"); } if ( rc3 ) { if ( (!rc) && (!rc2) ) rc = rc3; printk("presto: close files: lml filp won't close %d\n", rc3); } return rc;}int presto_fwrite(struct file *file, const char *str, int len, loff_t *off){ int rc; mm_segment_t old_fs; ENTRY; rc = -EINVAL; if ( !off ) { EXIT; return rc; } if ( ! file ) { EXIT; return rc; } if ( ! file->f_op ) { EXIT; return rc; } if ( ! file->f_op->write ) { EXIT; return rc; } old_fs = get_fs(); set_fs(get_ds()); rc = file->f_op->write(file, str, len, off); if (rc != len) { printk("presto_fwrite: wrote %d bytes instead of " "%d at %ld\n", rc, len, (long)*off); rc = -EIO; } set_fs(old_fs); EXIT; return rc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -