Viewing file: journal.c (66.28 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* * 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; }
int presto_fread(struct file *file, char *str, int len, loff_t *off) { int rc; mm_segment_t old_fs; ENTRY;
if ( len > 512 ) { printk("presto_fread: read at %Ld for %d bytes, ino %ld\n", *off, len, file->f_dentry->d_inode->i_ino); }
rc = -EINVAL; if ( !off ) { EXIT; return rc; }
if ( ! file ) { EXIT; return rc; }
if ( ! file->f_op ) { EXIT; return rc; }
if ( ! file->f_op->read ) { EXIT; return rc; }
old_fs = get_fs(); set_fs(get_ds()); rc = file->f_op->read(file, str, len, off); if (rc != len) { printk("presto_fread: read %d bytes instead of " "%d at %ld\n", rc, len, (long)*off); rc = -EIO; } set_fs(old_fs); return rc; }
static int presto_kml_dispatch(struct presto_file_set *fset) { int rc = 0; unsigned int kml_recno; struct presto_log_fd *fd = &fset->fset_kml; loff_t offset; ENTRY;
write_lock(&fd->fd_lock);
/* Determine the largest valid offset, i.e. up until the first * reservation held on the file. */ if ( !list_empty(&fd->fd_reservations) ) { struct presto_reservation_data *rd; rd = list_entry(fd->fd_reservations.next, struct presto_reservation_data, ri_list); offset = rd->ri_offset; kml_recno = rd->ri_recno; } else { offset = fd->fd_file->f_dentry->d_inode->i_size; kml_recno = fset->fset_kml.fd_recno; }
if ( kml_recno < fset->fset_lento_recno ) { printk("presto_kml_dispatch: smoke is coming\n"); write_unlock(&fd->fd_lock); return 0; } else if ( kml_recno == fset->fset_lento_recno ) { write_unlock(&fd->fd_lock); EXIT; return 0; } CDEBUG(D_PIOCTL, "fset: %s\n", fset->fset_name); rc = lento_kml(fset->fset_cache->cache_psdev->uc_minor, fset->fset_lento_off, fset->fset_lento_recno, offset, kml_recno, strlen(fset->fset_name), fset->fset_name);
if ( rc ) { write_unlock(&fd->fd_lock); EXIT; return rc; }
fset->fset_lento_off = offset; fset->fset_lento_recno = kml_recno; write_unlock(&fd->fd_lock); EXIT; return 0; }
/* structure of an extended log record:
buf-prefix buf-body [string1 [string2 [string3]]] buf-suffix
note: moves offset forward */ static inline int presto_write_record(struct file *f, loff_t *off, const char *buf, size_t size, const char *string1, int len1, const char *string2, int len2, const char *string3, int len3) { size_t prefix_size; int rc;
prefix_size = size - sizeof(struct journal_suffix); rc = presto_fwrite(f, buf, prefix_size, off); if ( rc != prefix_size ) { printk("Write error!\n"); EXIT; return -EIO; }
if ( string1 && len1 ) { rc = presto_fwrite(f, string1, len1, off); if ( rc != len1 ) { printk("Write error!\n"); EXIT; return -EIO; } }
if ( string2 && len2 ) { rc = presto_fwrite(f, string2, len2, off); if ( rc != len2 ) { printk("Write error!\n"); EXIT; return -EIO; } }
if ( string3 && len3 ) { rc = presto_fwrite(f, string3, len3, off); if ( rc != len3 ) { printk("Write error!\n"); EXIT; return -EIO; } }
rc = presto_fwrite(f, buf + prefix_size, sizeof(struct journal_suffix), off); if ( rc != sizeof(struct journal_suffix) ) { printk("Write error!\n"); EXIT; return -EIO; } return 0; }
/* * rec->size must be valid prior to calling this function. */ 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) { int rc; struct presto_reservation_data rd; loff_t offset; struct presto_log_fd *fd; struct journal_suffix *s; int prefix_size;
ENTRY;
/* buf is NULL when no_journal is in effect */ if (!buf) { EXIT; return -EINVAL; }
if (rec->is_kml) { fd = &fset->fset_kml; } else { fd = &fset->fset_lml; }
presto_reserve_record(fset, fd, rec, &rd); offset = rec->offset;
/* now we know the record number */ prefix_size = size - sizeof(struct journal_suffix); s = (struct journal_suffix *) (buf + prefix_size); s->recno = cpu_to_le32(rec->recno);
rc = presto_write_record(fd->fd_file, &offset, buf, size, string1, len1, string2, len2, string3, len3); if (rc) { printk("presto: error writing record to %s\n", rec->is_kml ? "KML" : "LML"); return rc; } presto_release_record(fd, &rd);
rc = presto_kml_dispatch(fset);
EXIT; return rc; }
/* read from the record at tail */ static int presto_last_record(struct presto_log_fd *fd, loff_t *size, loff_t *tail_offset, __u32 *recno, loff_t tail) { struct journal_suffix suffix; int rc; loff_t zeroes;
*recno = 0; *tail_offset = 0; *size = 0; if (tail < sizeof(struct journal_prefix) + sizeof(suffix)) { EXIT; return 0; }
zeroes = tail - sizeof(int); while ( zeroes >= 0 ) { int data; rc = presto_fread(fd->fd_file, (char *)&data, sizeof(data), &zeroes); if ( rc != sizeof(data) ) { rc = -EIO; return rc; } if (data) break; zeroes -= 2 * sizeof(data); }
/* zeroes at the begining of file. this is needed to prevent presto_fread errors -SHP */ if (zeroes <= 0) return 0; zeroes -= sizeof(suffix); rc = presto_fread(fd->fd_file, (char *)&suffix, sizeof(suffix), &zeroes); if ( rc != sizeof(suffix) ) { EXIT; return rc; } if ( suffix.len > 500 ) { printk("PRESTO: Warning long record tail at %ld, rec tail_offset at %ld (size %d)\n", (long) zeroes, (long)*tail_offset, suffix.len); }
*recno = suffix.recno; *size = suffix.len; *tail_offset = zeroes; return 0; }
static int presto_kml_last_recno(struct presto_file_set *fset) { int rc; loff_t size; loff_t tail_offset; int recno; loff_t tail = fset->fset_kml.fd_file->f_dentry->d_inode->i_size;
if ((rc = presto_last_record(&fset->fset_kml, &size, &tail_offset, &recno, tail)) ) { EXIT; return rc; }
fset->fset_kml.fd_offset = tail_offset; fset->fset_kml.fd_recno = recno; CDEBUG(D_JOURNAL, "setting fset_kml->fd_recno to %d, offset %Ld\n", recno, tail_offset); EXIT; return 0; }
static struct file *presto_log_open(struct presto_file_set *fset, char *name, int flags) { struct presto_cache *cache = fset->fset_cache; struct file *f; int error; int mtpt_len, path_len; char *path; ENTRY;
mtpt_len = strlen(cache->cache_mtpt); path_len = mtpt_len + strlen("/.intermezzo/") + strlen(fset->fset_name) + strlen(name);
error = -ENOMEM; PRESTO_ALLOC(path, char *, path_len + 1); if ( !path ) { EXIT; return ERR_PTR(-ENOMEM); }
sprintf(path, "%s/.intermezzo/%s/%s", cache->cache_mtpt, fset->fset_name, name); CDEBUG(D_INODE, "opening file %s\n", path);
f = filp_open(path, flags, 0); error = PTR_ERR(f); if (IS_ERR(f)) { CDEBUG(D_INODE, "Error %d\n", error); EXIT; goto out_free; }
error = -EINVAL; if ( cache != presto_get_cache(f->f_dentry->d_inode) ) { printk("PRESTO: %s cache does not match fset cache!\n", name); fset->fset_kml.fd_file = NULL; filp_close(f, NULL); goto out_free; }
if (cache->cache_filter && cache->cache_filter->o_trops && cache->cache_filter->o_trops->tr_journal_data) { CDEBUG(D_INODE, "\n"); cache->cache_filter->o_trops->tr_journal_data (f->f_dentry->d_inode); } else { printk("WARNING: InterMezzo no file data logging!\n"); }
out_free: PRESTO_FREE(path, path_len + 1);
EXIT; return f; }
int presto_init_kml_file(struct presto_file_set *fset) { int error = 0; struct file *f;
ENTRY; if (fset->fset_kml.fd_file) { CDEBUG(D_INODE, "fset already has KML open\n"); EXIT; return 0; }
fset->fset_kml.fd_lock = RW_LOCK_UNLOCKED; INIT_LIST_HEAD(&fset->fset_kml.fd_reservations); f = presto_log_open(fset, "kml", O_RDWR | O_CREAT); if ( IS_ERR(f) ) { error = PTR_ERR(f); return error; }
fset->fset_kml.fd_file = f; error = presto_kml_last_recno(fset);
if ( error ) { EXIT; fset->fset_kml.fd_file = NULL; filp_close(f, NULL); printk("presto: IO error in KML of fset %s\n", fset->fset_name); } fset->fset_lento_off = fset->fset_kml.fd_offset; fset->fset_lento_recno = fset->fset_kml.fd_recno;
EXIT; return error; }
int presto_init_last_rcvd_file(struct presto_file_set *fset) { int error = 0; struct file *f;
ENTRY; if (fset->fset_last_rcvd) { CDEBUG(D_INODE, "fset already has last_rcvd open\n"); EXIT; return 0; }
f = presto_log_open(fset, "last_rcvd", O_RDWR | O_CREAT); if ( IS_ERR(f) ) { error = PTR_ERR(f); return error; }
fset->fset_last_rcvd = f;
EXIT; return error; }
int presto_init_lml_file(struct presto_file_set *fset) { int error = 0; struct file *f;
ENTRY; if (fset->fset_lml.fd_file) { CDEBUG(D_INODE, "fset already has lml open\n"); EXIT; return 0; }
fset->fset_lml.fd_lock = RW_LOCK_UNLOCKED; INIT_LIST_HEAD(&fset->fset_lml.fd_reservations); f = presto_log_open(fset, "lml", O_RDWR | O_CREAT); if ( IS_ERR(f) ) { error = PTR_ERR(f); return error; }
fset->fset_lml.fd_file = f; fset->fset_lml.fd_offset = fset->fset_lml.fd_file->f_dentry->d_inode->i_size;
EXIT; return error; }
/* Write the last_rcvd values to the last)_rcvd file */ int presto_write_last_rcvd(struct rec_info *recinfo, struct presto_file_set *fset, struct lento_vfs_context *info) { int ret; loff_t off = info->slot_offset; struct { __u32 remote_recno; __u64 remote_offset; __u32 local_recno; __u64 local_offset; } rcvd_rec;
rcvd_rec.remote_recno = cpu_to_le32(info->recno); rcvd_rec.remote_offset = cpu_to_le64(info->kml_offset); rcvd_rec.local_recno = cpu_to_le32(recinfo->recno); rcvd_rec.local_offset = cpu_to_le64(recinfo->offset + recinfo->size);
ret = presto_fwrite(fset->fset_last_rcvd, (char *)(&rcvd_rec), sizeof(rcvd_rec), &off);
if (ret == sizeof(rcvd_rec)) ret = 0;
return ret; }
/* LML records here */ /* this writes the LML records for close, in conjunction with the KML */ int presto_write_lml_close(struct rec_info *rec, struct presto_file_set *fset, struct file *file, __u64 remote_ino, __u32 remote_generation, __u32 remote_version, struct presto_version *new_file_ver) { int opcode = PRESTO_OP_CLOSE; char *buffer; struct dentry *dentry = file->f_dentry; __u64 ino; __u32 pathlen; char *path; __u32 generation; int size; char *logrecord; char record[292]; struct dentry *root; int error;
ENTRY;
if ( presto_no_journal(fset) ) { EXIT; return 0; } root = fset->fset_mtpt;
BUFF_ALLOC(buffer, NULL); path = presto_path(dentry, root, buffer, PAGE_SIZE); CDEBUG(D_INODE, "Path: %s\n", path); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); ino = cpu_to_le64(dentry->d_inode->i_ino); generation = cpu_to_le32(dentry->d_inode->i_generation); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + sizeof(*new_file_ver) + sizeof(ino) + sizeof(generation) + sizeof(pathlen) + sizeof(remote_ino) + sizeof(remote_generation) + sizeof(remote_version) + sizeof(rec->offset) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 0; rec->size = size + size_round(le32_to_cpu(pathlen));
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver)); logrecord = logit(logrecord, &ino, sizeof(ino)); logrecord = logit(logrecord, &generation, sizeof(generation)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = logit(logrecord, &remote_ino, sizeof(remote_ino)); logrecord = logit(logrecord, &remote_generation, sizeof(remote_generation)); logrecord = logit(logrecord, &remote_version, sizeof(remote_version)); logrecord = logit(logrecord, &rec->offset, sizeof(rec->offset)); logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), NULL, 0, NULL, 0);
BUFF_FREE(buffer);
EXIT; return error; }
int presto_journal_write(struct rec_info *rec, struct presto_file_set *fset, struct file *file) { struct presto_version file_version; int rc; ENTRY;
presto_getversion(&file_version, file->f_dentry->d_inode); /* append this record */ rc = presto_write_lml_close (rec, fset, file, 0, /* remote_ino */ 0, /* remote_generation */ 0, /* remote_version */ &file_version); EXIT; return rc; }
/* * Check if the given record is at the end of the file. If it is, truncate * the lml to the record's offset, removing it. Repeat on prior record, * until we reach an active record or a reserved record (as defined by the * reservations list). */ static int presto_truncate_lml_tail(struct presto_file_set *fset) { loff_t lml_tail; loff_t lml_last_rec; loff_t lml_last_recsize; loff_t local_offset; int recno; struct journal_prefix prefix; struct inode *inode = fset->fset_lml.fd_file->f_dentry->d_inode; void *handle; int rc;
ENTRY; /* If someone else is already truncating the LML, return. */ write_lock(&fset->fset_lml.fd_lock); if (fset->fset_lml.fd_truncating == 1 ) { write_unlock(&fset->fset_lml.fd_lock); EXIT; return 0; } /* someone is about to write to the end of the LML */ if ( !list_empty(&fset->fset_lml.fd_reservations) ) { write_unlock(&fset->fset_lml.fd_lock); EXIT; return 0; } lml_tail = fset->fset_lml.fd_file->f_dentry->d_inode->i_size; /* Nothing to truncate?*/ if (lml_tail == 0) { write_unlock(&fset->fset_lml.fd_lock); EXIT; return 0; } fset->fset_lml.fd_truncating = 1; write_unlock(&fset->fset_lml.fd_lock);
presto_last_record(&fset->fset_lml, &lml_last_recsize, &lml_last_rec, &recno, lml_tail); /* Do we have a record to check? If not we have zeroes at the beginning of the file. -SHP */ if (lml_last_recsize != 0) { local_offset = lml_last_rec - lml_last_recsize; rc = presto_fread(fset->fset_lml.fd_file, (char *)&prefix, sizeof(prefix), &local_offset); if (rc != sizeof(prefix)) { EXIT; goto tr_out; } if ( prefix.opcode != PRESTO_OP_NOOP ) { EXIT; rc = 0; /* We may have zeroes at the end of the file, should we clear them out? -SHP */ goto tr_out; } } else lml_last_rec=0;
handle = presto_trans_start(fset, inode, PRESTO_OP_TRUNC); if ( !handle ) { EXIT; rc = -ENOMEM; goto tr_out; }
rc = presto_do_truncate(fset, fset->fset_lml.fd_file->f_dentry, lml_last_rec - lml_last_recsize, lml_tail); presto_trans_commit(fset, handle); if ( rc == 0 ) { rc = 1; } EXIT;
tr_out: CDEBUG(D_JOURNAL, "rc = %d\n", rc); write_lock(&fset->fset_lml.fd_lock); fset->fset_lml.fd_truncating = 0; write_unlock(&fset->fset_lml.fd_lock); return rc; }
int presto_truncate_lml(struct presto_file_set *fset) {
int rc; ENTRY; while ( (rc = presto_truncate_lml_tail(fset)) > 0); if ( rc < 0 && rc != -EALREADY) { printk("truncate_lml error %d\n", rc); } EXIT; return rc; }
int presto_clear_lml_close(struct presto_file_set *fset, loff_t lml_offset) { int rc; struct journal_prefix record; loff_t offset = lml_offset;
ENTRY;
if ( presto_no_journal(fset) ) { EXIT; return 0; }
CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %Zd\n", (long)lml_offset, sizeof(record)); rc = presto_fread(fset->fset_lml.fd_file, (char *)&record, sizeof(record), &offset);
if ( rc != sizeof(record) ) { printk("presto: clear_lml io error %d\n", rc); EXIT; return -EIO; }
/* overwrite the prefix */ CDEBUG(D_JOURNAL, "overwriting prefix: off %ld\n", (long)lml_offset); record.opcode = PRESTO_OP_NOOP; offset = lml_offset; /* note: this does just a single transaction in the cache */ rc = presto_fwrite(fset->fset_lml.fd_file, (char *)(&record), sizeof(record), &offset); if ( rc != sizeof(record) ) { EXIT; return -EIO; }
EXIT; return 0; }
/* now a journal function for every operation */
int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry, struct presto_version *old_ver, struct iattr *iattr) { int opcode = PRESTO_OP_SETATTR; char *buffer; char *path; __u32 pathlen; int size; char *logrecord; char record[292]; struct dentry *root; __u32 uid, gid, mode, valid, flags; __u64 fsize, mtime, ctime; int error;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) { EXIT; return 0; }
root = fset->fset_mtpt;
BUFF_ALLOC(buffer, NULL); path = presto_path(dentry, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + sizeof(*old_ver) + sizeof(valid) + sizeof(mode) + sizeof(uid) + sizeof(gid) + sizeof(fsize) + sizeof(mtime) + sizeof(ctime) + sizeof(flags) + sizeof(pathlen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); } /* Only journal one kind of mtime, and not atime at all. Also don't * journal bogus data in iattr, to make the journal more compressible. */ if (iattr->ia_valid & ATTR_MTIME_SET) iattr->ia_valid = iattr->ia_valid | ATTR_MTIME; valid = cpu_to_le32(iattr->ia_valid & ~(ATTR_ATIME | ATTR_MTIME_SET | ATTR_ATIME_SET)); mode = iattr->ia_valid & ATTR_MODE ? cpu_to_le32(iattr->ia_mode): 0; uid = iattr->ia_valid & ATTR_UID ? cpu_to_le32(iattr->ia_uid): 0; gid = iattr->ia_valid & ATTR_GID ? cpu_to_le32(iattr->ia_gid): 0; fsize = iattr->ia_valid & ATTR_SIZE ? cpu_to_le64(iattr->ia_size): 0; mtime = iattr->ia_valid & ATTR_MTIME ? cpu_to_le64(iattr->ia_mtime): 0; ctime = iattr->ia_valid & ATTR_CTIME ? cpu_to_le64(iattr->ia_ctime): 0; flags = iattr->ia_valid & ATTR_ATTR_FLAG ? cpu_to_le32(iattr->ia_attr_flags): 0;
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen));
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, old_ver, sizeof(*old_ver)); logrecord = logit(logrecord, &valid, sizeof(valid)); logrecord = logit(logrecord, &mode, sizeof(mode)); logrecord = logit(logrecord, &uid, sizeof(uid)); logrecord = logit(logrecord, &gid, sizeof(gid)); logrecord = logit(logrecord, &fsize, sizeof(fsize)); logrecord = logit(logrecord, &mtime, sizeof(mtime)); logrecord = logit(logrecord, &ctime, sizeof(ctime)); logrecord = logit(logrecord, &flags, sizeof(flags)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), NULL, 0, NULL, 0);
BUFF_FREE(buffer); EXIT; return error; }
int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry, struct presto_version *tgt_dir_ver, struct presto_version *new_file_ver, int mode) { int opcode = PRESTO_OP_CREATE; char *buffer; char *path; __u32 pathlen; int size; char *logrecord; char record[292]; struct dentry *root; __u32 uid, gid, lmode; int error;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
root = fset->fset_mtpt;
uid = cpu_to_le32(dentry->d_inode->i_uid); gid = cpu_to_le32(dentry->d_inode->i_gid); lmode = cpu_to_le32(mode); BUFF_ALLOC(buffer, NULL); path = presto_path(dentry, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) + sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen));
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver)); logrecord = log_version(logrecord, dentry->d_parent); logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver)); logrecord = logit(logrecord, &lmode, sizeof(lmode)); logrecord = logit(logrecord, &uid, sizeof(uid)); logrecord = logit(logrecord, &gid, sizeof(gid)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), NULL, 0, NULL, 0);
BUFF_FREE(buffer); EXIT; return error; }
int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry, const char *target, struct presto_version *tgt_dir_ver, struct presto_version *new_link_ver) { int opcode = PRESTO_OP_SYMLINK; char *buffer; char *path; __u32 pathlen; int size; char *logrecord; char record[292]; __u32 targetlen = cpu_to_le32(strlen(target)); struct dentry *root; __u32 uid, gid; int error;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
root = fset->fset_mtpt;
uid = cpu_to_le32(dentry->d_inode->i_uid); gid = cpu_to_le32(dentry->d_inode->i_gid);
BUFF_ALLOC(buffer, NULL); path = presto_path(dentry, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) + sizeof(targetlen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(le32_to_cpu(targetlen));
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver)); logrecord = log_version(logrecord, dentry->d_parent); logrecord = logit(logrecord, new_link_ver, sizeof(*new_link_ver)); logrecord = logit(logrecord, &uid, sizeof(uid)); logrecord = logit(logrecord, &gid, sizeof(gid)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = logit(logrecord, &targetlen, sizeof(targetlen)); logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), target, size_round(le32_to_cpu(targetlen)), NULL, 0);
BUFF_FREE(buffer); EXIT; return error; }
int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry, struct presto_version *tgt_dir_ver, struct presto_version *new_dir_ver, int mode) { int opcode = PRESTO_OP_MKDIR; char *buffer; char *path; __u32 pathlen; int size; char *logrecord; char record[292]; struct dentry *root; __u32 uid, gid, lmode; int error;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
root = fset->fset_mtpt;
uid = cpu_to_le32(dentry->d_inode->i_uid); gid = cpu_to_le32(dentry->d_inode->i_gid); lmode = cpu_to_le32(mode);
BUFF_ALLOC(buffer, NULL); path = presto_path(dentry, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) + sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen)); logrecord = journal_log_prefix(record, opcode, rec);
logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver)); logrecord = log_version(logrecord, dentry->d_parent); logrecord = logit(logrecord, new_dir_ver, sizeof(*new_dir_ver)); logrecord = logit(logrecord, &lmode, sizeof(lmode)); logrecord = logit(logrecord, &uid, sizeof(uid)); logrecord = logit(logrecord, &gid, sizeof(gid)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), NULL, 0, NULL, 0);
BUFF_FREE(buffer); EXIT; return error; }
int presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dir, struct presto_version *tgt_dir_ver, struct presto_version *old_dir_ver, int len, const char *name) { int opcode = PRESTO_OP_RMDIR; char *buffer; char *path; __u32 pathlen, llen; int size; char *logrecord; char record[292]; struct dentry *root; int error;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
root = fset->fset_mtpt;
llen = cpu_to_le32(len); BUFF_ALLOC(buffer, NULL); path = presto_path(dir, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) + sizeof(pathlen) + sizeof(llen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
CDEBUG(D_JOURNAL, "path: %s (%d), name: %s (%d), size %d\n", path, pathlen, name, len, size);
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(len);
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver)); logrecord = log_version(logrecord, dir); logrecord = logit(logrecord, old_dir_ver, sizeof(*old_dir_ver)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = logit(logrecord, &llen, sizeof(llen)); logrecord = journal_log_suffix(logrecord, record, fset, dir, rec); error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), name, size_round(len), NULL, 0);
BUFF_FREE(buffer); EXIT; return error; }
int presto_journal_mknod(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry, struct presto_version *tgt_dir_ver, struct presto_version *new_node_ver, int mode, int dmajor, int dminor ) { int opcode = PRESTO_OP_MKNOD; char *buffer; char *path; __u32 pathlen; int size; char *logrecord; char record[292]; struct dentry *root; __u32 uid, gid, lmode, lmajor, lminor; int error;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
root = fset->fset_mtpt;
uid = cpu_to_le32(dentry->d_inode->i_uid); gid = cpu_to_le32(dentry->d_inode->i_gid); lmode = cpu_to_le32(mode); lmajor = cpu_to_le32(dmajor); lminor = cpu_to_le32(dminor);
BUFF_ALLOC(buffer, NULL); path = presto_path(dentry, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) + sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(lmajor) + sizeof(lminor) + sizeof(pathlen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen));
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver)); logrecord = log_version(logrecord, dentry->d_parent); logrecord = logit(logrecord, new_node_ver, sizeof(*new_node_ver)); logrecord = logit(logrecord, &lmode, sizeof(lmode)); logrecord = logit(logrecord, &uid, sizeof(uid)); logrecord = logit(logrecord, &gid, sizeof(gid)); logrecord = logit(logrecord, &lmajor, sizeof(lmajor)); logrecord = logit(logrecord, &lminor, sizeof(lminor)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), NULL, 0, NULL, 0);
BUFF_FREE(buffer); EXIT; return error; }
int presto_journal_link(struct rec_info *rec, struct presto_file_set *fset, struct dentry *src, struct dentry *tgt, struct presto_version *tgt_dir_ver, struct presto_version *new_link_ver) { int opcode = PRESTO_OP_LINK; char *buffer, *srcbuffer; char *path, *srcpath; __u32 pathlen, srcpathlen; int size; char *logrecord; char record[292]; struct dentry *root; int error;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
root = fset->fset_mtpt;
BUFF_ALLOC(srcbuffer, NULL); srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE); srcpathlen = cpu_to_le32(MYPATHLEN(srcbuffer, srcpath));
BUFF_ALLOC(buffer, srcbuffer); path = presto_path(tgt, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) + sizeof(srcpathlen) + sizeof(pathlen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(le32_to_cpu(srcpathlen));
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver)); logrecord = log_version(logrecord, tgt->d_parent); logrecord = logit(logrecord, new_link_ver, sizeof(*new_link_ver)); logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec);
error = presto_log(fset, rec, record, size, srcpath, size_round(le32_to_cpu(srcpathlen)), path, size_round(le32_to_cpu(pathlen)), NULL, 0);
BUFF_FREE(srcbuffer); BUFF_FREE(buffer); EXIT; return error; }
int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset, struct dentry *src, struct dentry *tgt, struct presto_version *src_dir_ver, struct presto_version *tgt_dir_ver) { int opcode = PRESTO_OP_RENAME; char *buffer, *srcbuffer; char *path, *srcpath; __u32 pathlen, srcpathlen; int size; char *logrecord; char record[292]; struct dentry *root; int error;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
root = fset->fset_mtpt;
BUFF_ALLOC(srcbuffer, NULL); srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE); srcpathlen = cpu_to_le32(MYPATHLEN(srcbuffer, srcpath));
BUFF_ALLOC(buffer, srcbuffer); path = presto_path(tgt, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + 4 * sizeof(*src_dir_ver) + sizeof(srcpathlen) + sizeof(pathlen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(le32_to_cpu(srcpathlen));
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, src_dir_ver, sizeof(*src_dir_ver)); logrecord = log_version(logrecord, src->d_parent); logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver)); logrecord = log_version(logrecord, tgt->d_parent); logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec);
error = presto_log(fset, rec, record, size, srcpath, size_round(le32_to_cpu(srcpathlen)), path, size_round(le32_to_cpu(pathlen)), NULL, 0);
BUFF_FREE(buffer); BUFF_FREE(srcbuffer); EXIT; return error; }
int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dir, struct presto_version *tgt_dir_ver, struct presto_version *old_file_ver, int len, const char *name) { int opcode = PRESTO_OP_UNLINK; char *buffer; char *path; __u32 pathlen, llen; int size; char *logrecord; char record[292]; struct dentry *root; int error;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
root = fset->fset_mtpt;
llen = cpu_to_le32(len); BUFF_ALLOC(buffer, NULL); path = presto_path(dir, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) + sizeof(pathlen) + sizeof(llen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(len);
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver)); logrecord = log_version(logrecord, dir); logrecord = logit(logrecord, old_file_ver, sizeof(*old_file_ver)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = logit(logrecord, &llen, sizeof(llen)); logrecord = journal_log_suffix(logrecord, record, fset, dir, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), name, size_round(len), NULL, 0);
BUFF_FREE(buffer); EXIT; return error; }
int presto_journal_close(struct rec_info *rec, struct presto_file_set *fset, struct file *file, struct dentry *dentry, struct presto_version *new_file_ver) { int opcode = PRESTO_OP_CLOSE; struct presto_file_data *fd; char *buffer; char *path; __u64 ino; __u32 pathlen; __u32 generation; int size; char *logrecord; char record[292]; struct dentry *root; int error; __u32 open_fsuid; __u32 open_fsgid; __u32 open_ngroups; __u32 open_groups[NGROUPS_MAX]; __u32 open_mode; __u32 open_uid; __u32 open_gid; int i;
ENTRY;
if ( presto_no_journal(fset) ) { EXIT; return 0; }
if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) { EXIT; return 0; }
root = fset->fset_mtpt;
fd = (struct presto_file_data *)file->private_data; if (fd) { open_ngroups = fd->fd_ngroups; for (i = 0; i < fd->fd_ngroups; i++) open_groups[i] = (__u32) fd->fd_groups[i]; open_mode = fd->fd_mode; open_uid = fd->fd_uid; open_gid = fd->fd_gid; open_fsuid = fd->fd_fsuid; open_fsgid = fd->fd_fsgid; } else { open_ngroups = current->ngroups; for (i=0; i<current->ngroups; i++) open_groups[i] = (__u32) current->groups[i]; open_mode = dentry->d_inode->i_mode; open_uid = dentry->d_inode->i_uid; open_gid = dentry->d_inode->i_gid; open_fsuid = current->fsuid; open_fsgid = current->fsgid; } BUFF_ALLOC(buffer, NULL); path = presto_path(dentry, root, buffer, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); ino = cpu_to_le64(dentry->d_inode->i_ino); generation = cpu_to_le32(dentry->d_inode->i_generation); size = sizeof(__u32) * open_ngroups + sizeof(open_mode) + sizeof(open_uid) + sizeof(open_gid) + sizeof(struct journal_prefix) + sizeof(*new_file_ver) + sizeof(ino) + sizeof(generation) + sizeof(pathlen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen));
logrecord = journal_log_prefix_with_groups_and_ids( record, opcode, rec, open_ngroups, open_groups, open_fsuid, open_fsgid); logrecord = logit(logrecord, &open_mode, sizeof(open_mode)); logrecord = logit(logrecord, &open_uid, sizeof(open_uid)); logrecord = logit(logrecord, &open_gid, sizeof(open_gid)); logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver)); logrecord = logit(logrecord, &ino, sizeof(ino)); logrecord = logit(logrecord, &generation, sizeof(generation)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), NULL, 0, NULL, 0); BUFF_FREE(buffer);
EXIT; return error; }
int presto_rewrite_close(struct rec_info *rec, struct presto_file_set *fset, char *path, __u32 pathlen, int ngroups, __u32 *groups, __u64 ino, __u32 generation, struct presto_version *new_file_ver) { int opcode = PRESTO_OP_CLOSE; int size; char *logrecord; char record[292]; struct dentry *root; int error;
ENTRY;
if ( presto_no_journal(fset) ) { EXIT; return 0; }
root = fset->fset_mtpt;
size = sizeof(__u32) * ngroups + sizeof(struct journal_prefix) + sizeof(*new_file_ver) + sizeof(ino) + sizeof(generation) + sizeof(le32_to_cpu(pathlen)) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; rec->size = size + size_round(le32_to_cpu(pathlen));
logrecord = journal_log_prefix_with_groups(record, opcode, rec, ngroups, groups); logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver)); logrecord = logit(logrecord, &ino, sizeof(ino)); logrecord = logit(logrecord, &generation, sizeof(generation)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = journal_log_suffix(logrecord, record, fset, NULL, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), NULL, 0, NULL, 0);
EXIT; return error; }
/* write closes for the local close records in the LML */ int presto_complete_lml(struct presto_file_set *fset) { __u32 groups[NGROUPS_MAX]; loff_t lml_offset; loff_t read_offset; char *buffer; void *handle; struct rec_info rec; struct close_rec { struct presto_version new_file_ver; __u64 ino; __u32 generation; __u32 pathlen; __u64 remote_ino; __u32 remote_generation; __u32 remote_version; __u64 lml_offset; } close_rec; struct file *file = fset->fset_lml.fd_file; struct journal_prefix prefix; int rc = 0; ENTRY;
lml_offset = 0; again: if (lml_offset >= file->f_dentry->d_inode->i_size) { EXIT; return rc; }
read_offset = lml_offset; rc = presto_fread(file, (char *)&prefix, sizeof(prefix), &read_offset); if ( rc != sizeof(prefix) ) { EXIT; printk("presto_complete_lml: ioerror - 1, tell Peter\n"); return -EIO; }
if ( prefix.opcode == PRESTO_OP_NOOP ) { lml_offset += prefix.len; goto again; }
rc = presto_fread(file, (char *)groups, prefix.ngroups * sizeof(__u32), &read_offset); if ( rc != prefix.ngroups * sizeof(__u32) ) { EXIT; printk("presto_complete_lml: ioerror - 2, tell Peter\n"); return -EIO; }
rc = presto_fread(file, (char *)&close_rec, sizeof(close_rec), &read_offset); if ( rc != sizeof(close_rec) ) { EXIT; printk("presto_complete_lml: ioerror - 3, tell Peter\n"); return -EIO; }
/* is this a backfetch or a close record? */ if ( le64_to_cpu(close_rec.remote_ino) != 0 ) { lml_offset += prefix.len; goto again; }
BUFF_ALLOC(buffer, NULL); rc = presto_fread(file, (char *)buffer, le32_to_cpu(close_rec.pathlen), &read_offset); if ( rc != le32_to_cpu(close_rec.pathlen) ) { EXIT; printk("presto_complete_lml: ioerror - 4, tell Peter\n"); return -EIO; } handle = presto_trans_start(fset, file->f_dentry->d_inode, PRESTO_OP_RELEASE); if ( !handle ) { EXIT; return -ENOMEM; }
rc = presto_clear_lml_close(fset, lml_offset); if ( rc ) { printk("error during clearing: %d\n", rc); presto_trans_commit(fset, handle); EXIT; return rc; }
rc = presto_rewrite_close(&rec, fset, buffer, close_rec.pathlen, prefix.ngroups, groups, close_rec.ino, close_rec.generation, &close_rec.new_file_ver); if ( rc ) { printk("error during rewrite close: %d\n", rc); presto_trans_commit(fset, handle); EXIT; return rc; }
presto_trans_commit(fset, handle); if ( rc ) { printk("error during truncation: %d\n", rc); EXIT; return rc; } lml_offset += prefix.len; CDEBUG(D_JOURNAL, "next LML record at: %ld\n", (long)lml_offset); goto again;
EXIT; return -EINVAL; }
#ifdef CONFIG_FS_EXT_ATTR /* Journal an ea operation. A NULL buffer implies the attribute is * getting deleted. In this case we simply change the opcode, but nothing * else is affected. */ int presto_journal_set_ext_attr (struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry, struct presto_version *ver, const char *name, const char *buffer, int buffer_len, int flags) { int opcode = (buffer == NULL) ? PRESTO_OP_DELEXTATTR : PRESTO_OP_SETEXTATTR ; char *temp; char *path; __u32 pathlen; int size; char *logrecord; char record[292]; struct dentry *root; int error; __u32 namelen=cpu_to_le32(strnlen(name,PRESTO_EXT_ATTR_NAME_MAX)); __u32 buflen=(buffer != NULL)? cpu_to_le32(buffer_len): cpu_to_le32(0); __u32 mode;
ENTRY; if ( presto_no_journal(fset) ) { EXIT; return 0; }
if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) { EXIT; return 0; }
root = fset->fset_mtpt;
BUFF_ALLOC(temp, NULL); path = presto_path(dentry, root, temp, PAGE_SIZE); pathlen = cpu_to_le32(MYPATHLEN(temp, path));
flags=cpu_to_le32(flags); /* Ugly, but needed. posix ACLs change the mode without using * setattr, we need to record these changes. The EA code per se * is not really affected. */ mode=cpu_to_le32(dentry->d_inode->i_mode);
size = sizeof(__u32) * current->ngroups + sizeof(struct journal_prefix) + 2 * sizeof(struct presto_version) + sizeof(flags) + sizeof(mode) + sizeof(namelen) + sizeof(buflen) + sizeof(pathlen) + sizeof(struct journal_suffix);
if ( size > sizeof(record) ) { printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__); }
rec->is_kml = 1; /* Make space for a path, a attr name and value*/ /* We use the buflen instead of buffer_len to make sure that we * journal the right length. This may be a little paranoid, but * with 64 bits round the corner, I would rather be safe than sorry! * Also this handles deletes with non-zero buffer_lengths correctly. * SHP */ rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(le32_to_cpu(namelen)) + size_round(le32_to_cpu(buflen));
logrecord = journal_log_prefix(record, opcode, rec); logrecord = logit(logrecord, ver, sizeof(*ver)); logrecord = log_version(logrecord, dentry); logrecord = logit(logrecord, &flags, sizeof(flags)); logrecord = logit(logrecord, &mode, sizeof(flags)); logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); logrecord = logit(logrecord, &namelen, sizeof(namelen)); logrecord = logit(logrecord, &buflen, sizeof(buflen)); logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
error = presto_log(fset, rec, record, size, path, size_round(le32_to_cpu(pathlen)), name, size_round(le32_to_cpu(namelen)), buffer, size_round(le32_to_cpu(buflen)));
BUFF_FREE(temp); EXIT; return error; } #endif
|