file.c 18.2 KB
Newer Older
Robert Read's avatar
Robert Read committed
1 2
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
 * vim:expandtab:shiftwidth=8:tabstop=8:
Linus Torvalds's avatar
Linus Torvalds committed
3 4 5 6 7
 *
 *  Copyright (C) 2000 Stelias Computing, Inc.
 *  Copyright (C) 2000 Red Hat, Inc.
 *  Copyright (C) 2000 TurboLinux, Inc.
 *  Copyright (C) 2000 Los Alamos National Laboratory.
Robert Read's avatar
Robert Read committed
8
 *  Copyright (C) 2000, 2001 Tacit Networks, Inc.
Linus Torvalds's avatar
Linus Torvalds committed
9 10 11 12
 *  Copyright (C) 2000 Peter J. Braam
 *  Copyright (C) 2001 Mountain View Data, Inc. 
 *  Copyright (C) 2001 Cluster File Systems, Inc. 
 *
Robert Read's avatar
Robert Read committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *   This file is part of InterMezzo, http://www.inter-mezzo.org.
 *
 *   InterMezzo is free software; you can redistribute it and/or
 *   modify it under the terms of version 2 of the GNU General Public
 *   License as published by the Free Software Foundation.
 *
 *   InterMezzo is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with InterMezzo; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Linus Torvalds's avatar
Linus Torvalds committed
27
 *
Robert Read's avatar
Robert Read committed
28 29
 *  This file manages file I/O
 * 
Linus Torvalds's avatar
Linus Torvalds committed
30 31 32 33 34 35 36 37 38 39 40 41 42
 */

#include <stdarg.h>

#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/system.h>

#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
Robert Read's avatar
Robert Read committed
43
#include <linux/sched.h>
Linus Torvalds's avatar
Linus Torvalds committed
44 45
#include <linux/stat.h>
#include <linux/string.h>
Robert Read's avatar
Robert Read committed
46
#include <linux/smp_lock.h>
Linus Torvalds's avatar
Linus Torvalds committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#define __NO_VERSION__
#include <linux/module.h>

#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#include <linux/fsfilter.h>
/*
 * these are initialized in super.c
 */
extern int presto_permission(struct inode *inode, int mask);


static int presto_open_upcall(int minor, struct dentry *de)
{
        int rc;
        char *path, *buffer;
Robert Read's avatar
Robert Read committed
66
        struct presto_file_set *fset;
Linus Torvalds's avatar
Linus Torvalds committed
67
        int pathlen;
Robert Read's avatar
Robert Read committed
68 69
        struct lento_vfs_context info;
        struct presto_dentry_data *dd = presto_d2d(de);
Linus Torvalds's avatar
Linus Torvalds committed
70

Robert Read's avatar
Robert Read committed
71
        PRESTO_ALLOC(buffer, PAGE_SIZE);
Linus Torvalds's avatar
Linus Torvalds committed
72
        if ( !buffer ) {
Robert Read's avatar
Robert Read committed
73 74
                CERROR("PRESTO: out of memory!\n");
                return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
75
        }
Robert Read's avatar
Robert Read committed
76 77
        fset = presto_fset(de);
        path = presto_path(de, fset->fset_dentry, buffer, PAGE_SIZE);
Linus Torvalds's avatar
Linus Torvalds committed
78
        pathlen = MYPATHLEN(buffer, path);
Robert Read's avatar
Robert Read committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92
        
        CDEBUG(D_FILE, "de %p, dd %p\n", de, dd);
        if (dd->remote_ino == 0) {
                rc = presto_get_fileid(minor, fset, de);
        }
        memset (&info, 0, sizeof(info));
        if (dd->remote_ino > 0) {
                info.remote_ino = dd->remote_ino;
                info.remote_generation = dd->remote_generation;
        } else
                CERROR("get_fileid failed %d, ino: %Lx, fetching by name\n", rc,
                       dd->remote_ino);

        rc = izo_upc_open(minor, pathlen, path, fset->fset_name, &info);
Linus Torvalds's avatar
Linus Torvalds committed
93 94 95 96
        PRESTO_FREE(buffer, PAGE_SIZE);
        return rc;
}

Robert Read's avatar
Robert Read committed
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
static inline int open_check_dod(struct file *file,
                                 struct presto_file_set *fset)
{
        int gen, is_iopen = 0, minor;
        struct presto_cache *cache = fset->fset_cache;
        ino_t inum;

        minor = presto_c2m(cache);

        if ( ISLENTO(minor) ) {
                CDEBUG(D_CACHE, "is lento, not doing DOD.\n");
                return 0;
        }

        /* Files are only ever opened by inode during backfetches, when by
         * definition we have the authoritative copy of the data.  No DOD. */
        is_iopen = izo_dentry_is_ilookup(file->f_dentry, &inum, &gen);

        if (is_iopen) {
                CDEBUG(D_CACHE, "doing iopen, not doing DOD.\n");
                return 0;
        }

        if (!(fset->fset_flags & FSET_DATA_ON_DEMAND)) {
                CDEBUG(D_CACHE, "fileset not on demand.\n");
                return 0;
        }
                
        if (file->f_flags & O_TRUNC) {
                CDEBUG(D_CACHE, "fileset dod: O_TRUNC.\n");
                return 0;
        }
                
        if (presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL)) {
                CDEBUG(D_CACHE, "file under .intermezzo, not doing DOD\n");
                return 0;
        }

        if (presto_chk(file->f_dentry, PRESTO_DATA)) {
                CDEBUG(D_CACHE, "PRESTO_DATA is set, not doing DOD.\n");
                return 0;
        }

        if (cache->cache_filter->o_trops->tr_all_data(file->f_dentry->d_inode)) {
                CDEBUG(D_CACHE, "file not sparse, not doing DOD.\n");
                return 0;
        }

        return 1;
}
Linus Torvalds's avatar
Linus Torvalds committed
147 148 149 150 151 152

static int presto_file_open(struct inode *inode, struct file *file)
{
        int rc = 0;
        struct file_operations *fops;
        struct presto_cache *cache;
Robert Read's avatar
Robert Read committed
153
        struct presto_file_set *fset;
Linus Torvalds's avatar
Linus Torvalds committed
154 155
        struct presto_file_data *fdata;
        int writable = (file->f_flags & (O_RDWR | O_WRONLY));
Robert Read's avatar
Robert Read committed
156
        int minor, i;
Linus Torvalds's avatar
Linus Torvalds committed
157 158 159

        ENTRY;

Robert Read's avatar
Robert Read committed
160
        if (presto_prep(file->f_dentry, &cache, &fset) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
161 162 163 164 165 166
                EXIT;
                return -EBADF;
        }

        minor = presto_c2m(cache);

Robert Read's avatar
Robert Read committed
167 168 169
        CDEBUG(D_CACHE, "DATA_OK: %d, ino: %ld, islento: %d\n",
               presto_chk(file->f_dentry, PRESTO_DATA), inode->i_ino,
               ISLENTO(minor));
Linus Torvalds's avatar
Linus Torvalds committed
170

Robert Read's avatar
Robert Read committed
171 172 173
        if ( !ISLENTO(minor) && (file->f_flags & O_RDWR ||
                                 file->f_flags & O_WRONLY)) {
                CDEBUG(D_CACHE, "calling presto_get_permit\n");
Linus Torvalds's avatar
Linus Torvalds committed
174 175 176 177 178 179 180
                if ( presto_get_permit(inode) < 0 ) {
                        EXIT;
                        return -EROFS;
                }
                presto_put_permit(inode);
        }

Robert Read's avatar
Robert Read committed
181 182 183 184
        if (open_check_dod(file, fset)) {
                CDEBUG(D_CACHE, "presto_open_upcall\n");
                CDEBUG(D_CACHE, "dentry: %p setting DATA, ATTR\n", file->f_dentry);
                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
Linus Torvalds's avatar
Linus Torvalds committed
185
                rc = presto_open_upcall(minor, file->f_dentry);
Robert Read's avatar
Robert Read committed
186 187 188 189 190 191 192 193 194 195 196 197
                if (rc) {
                        EXIT;
                        CERROR("%s: returning error %d\n", __FUNCTION__, rc);
                        return rc;
                }

        }

        /* file was truncated upon open: do not refetch */
        if (file->f_flags & O_TRUNC) { 
                CDEBUG(D_CACHE, "setting DATA, ATTR\n");
                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
Linus Torvalds's avatar
Linus Torvalds committed
198 199 200 201
        }

        fops = filter_c2cffops(cache->cache_filter);
        if ( fops->open ) {
Robert Read's avatar
Robert Read committed
202
                CDEBUG(D_CACHE, "calling fs open\n");
Linus Torvalds's avatar
Linus Torvalds committed
203 204
                rc = fops->open(inode, file);

Robert Read's avatar
Robert Read committed
205 206 207 208 209
                if (rc) {
                        EXIT;
                        return rc;
                }
        }
Linus Torvalds's avatar
Linus Torvalds committed
210

Robert Read's avatar
Robert Read committed
211 212
        if (writable) {
                PRESTO_ALLOC(fdata, sizeof(*fdata));
Linus Torvalds's avatar
Linus Torvalds committed
213 214 215 216
                if (!fdata) {
                        EXIT;
                        return -ENOMEM;
                }
Robert Read's avatar
Robert Read committed
217
                /* LOCK: XXX check that the kernel lock protects this alloc */
Linus Torvalds's avatar
Linus Torvalds committed
218
                fdata->fd_do_lml = 0;
Robert Read's avatar
Robert Read committed
219
                fdata->fd_bytes_written = 0;
Linus Torvalds's avatar
Linus Torvalds committed
220 221 222
                fdata->fd_fsuid = current->fsuid;
                fdata->fd_fsgid = current->fsgid;
                fdata->fd_mode = file->f_dentry->d_inode->i_mode;
Robert Read's avatar
Robert Read committed
223 224
                fdata->fd_uid = file->f_dentry->d_inode->i_uid;
                fdata->fd_gid = file->f_dentry->d_inode->i_gid;
Linus Torvalds's avatar
Linus Torvalds committed
225
                fdata->fd_ngroups = current->ngroups;
Robert Read's avatar
Robert Read committed
226 227 228 229 230 231 232 233 234 235 236 237
                for (i=0 ; i < current->ngroups ; i++)
                        fdata->fd_groups[i] = current->groups[i];
                if (!ISLENTO(minor)) 
                        fdata->fd_info.flags = LENTO_FL_KML; 
                else { 
                        /* this is for the case of DOD, 
                           reint_close will adjust flags if needed */
                        fdata->fd_info.flags = 0;
                }

                presto_getversion(&fdata->fd_version, inode);
                file->private_data = fdata;
Linus Torvalds's avatar
Linus Torvalds committed
238 239 240 241
        } else {
                file->private_data = NULL;
        }

Robert Read's avatar
Robert Read committed
242
        EXIT;
Linus Torvalds's avatar
Linus Torvalds committed
243 244 245
        return 0;
}

Robert Read's avatar
Robert Read committed
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
int presto_adjust_lml(struct file *file, struct lento_vfs_context *info)
{
        struct presto_file_data *fdata = 
                (struct presto_file_data *) file->private_data;

        if (!fdata) { 
                EXIT;
                return -EINVAL;
        }
                
        memcpy(&fdata->fd_info, info, sizeof(*info));
        EXIT;
        return 0; 
}


Linus Torvalds's avatar
Linus Torvalds committed
262 263 264 265 266 267 268 269 270
static int presto_file_release(struct inode *inode, struct file *file)
{
        int rc;
        struct file_operations *fops;
        struct presto_cache *cache;
        struct presto_file_set *fset;
        struct presto_file_data *fdata = 
                (struct presto_file_data *)file->private_data;
        ENTRY;
Robert Read's avatar
Robert Read committed
271

Linus Torvalds's avatar
Linus Torvalds committed
272 273 274 275 276 277 278
        rc = presto_prep(file->f_dentry, &cache, &fset);
        if ( rc ) {
                EXIT;
                return rc;
        }

        fops = filter_c2cffops(cache->cache_filter);
Robert Read's avatar
Robert Read committed
279 280
        if (fops && fops->release)
                rc = fops->release(inode, file);
Linus Torvalds's avatar
Linus Torvalds committed
281

Robert Read's avatar
Robert Read committed
282
        CDEBUG(D_CACHE, "islento = %d (minor %d), rc %d, data %p\n",
Linus Torvalds's avatar
Linus Torvalds committed
283
               ISLENTO(cache->cache_psdev->uc_minor), 
Robert Read's avatar
Robert Read committed
284
               cache->cache_psdev->uc_minor, rc, fdata);
Linus Torvalds's avatar
Linus Torvalds committed
285

Robert Read's avatar
Robert Read committed
286 287
        /* this file was modified: ignore close errors, write KML */
        if (fdata && fdata->fd_do_lml) {
Linus Torvalds's avatar
Linus Torvalds committed
288 289 290 291 292 293
                /* XXX: remove when lento gets file granularity cd */
                if ( presto_get_permit(inode) < 0 ) {
                        EXIT;
                        return -EROFS;
                }
        
Robert Read's avatar
Robert Read committed
294 295
                fdata->fd_info.updated_time = file->f_dentry->d_inode->i_mtime;
                rc = presto_do_close(fset, file); 
Linus Torvalds's avatar
Linus Torvalds committed
296 297 298 299 300
                presto_put_permit(inode);
        }

        if (!rc && fdata) {
                PRESTO_FREE(fdata, sizeof(*fdata));
Robert Read's avatar
Robert Read committed
301
                file->private_data = NULL; 
Linus Torvalds's avatar
Linus Torvalds committed
302 303 304 305 306 307
        }
        
        EXIT;
        return rc;
}

Robert Read's avatar
Robert Read committed
308 309
static void presto_apply_write_policy(struct file *file,
                                      struct presto_file_set *fset, loff_t res)
Linus Torvalds's avatar
Linus Torvalds committed
310
{
Robert Read's avatar
Robert Read committed
311 312
        struct presto_file_data *fdata =
                (struct presto_file_data *)file->private_data;
Linus Torvalds's avatar
Linus Torvalds committed
313 314 315 316 317 318 319 320 321 322 323 324
        struct presto_cache *cache = fset->fset_cache;
        struct presto_version new_file_ver;
        int error;
        struct rec_info rec;

        /* Here we do a journal close after a fixed or a specified
         amount of KBytes, currently a global parameter set with
         sysctl. If files are open for a long time, this gives added
         protection. (XXX todo: per cache, add ioctl, handle
         journaling in a thread, add more options etc.)
        */ 
 
Robert Read's avatar
Robert Read committed
325 326 327
        if ((fset->fset_flags & FSET_JCLOSE_ON_WRITE) &&
            (!ISLENTO(cache->cache_psdev->uc_minor))) {
                fdata->fd_bytes_written += res;
Linus Torvalds's avatar
Linus Torvalds committed
328
 
Robert Read's avatar
Robert Read committed
329 330 331
                if (fdata->fd_bytes_written >= fset->fset_file_maxio) {
                        presto_getversion(&new_file_ver,
                                          file->f_dentry->d_inode);
Linus Torvalds's avatar
Linus Torvalds committed
332 333 334 335 336 337
                        /* This is really heavy weight and should be fixed
                           ASAP. At most we should be recording the number
                           of bytes written and not locking the kernel, 
                           wait for permits, etc, on the write path. SHP
                        */
                        lock_kernel();
Robert Read's avatar
Robert Read committed
338 339 340 341
                        if ( presto_get_permit(file->f_dentry->d_inode) < 0 ) {
                                EXIT;
                                /* we must be disconnected, not to worry */
                                unlock_kernel();
Linus Torvalds's avatar
Linus Torvalds committed
342
                                return; 
Robert Read's avatar
Robert Read committed
343 344 345 346 347 348
                        }
                        error = presto_journal_close(&rec, fset, file,
                                                     file->f_dentry,
                                                     &fdata->fd_version,
                                                     &new_file_ver);
                        presto_put_permit(file->f_dentry->d_inode);
Linus Torvalds's avatar
Linus Torvalds committed
349
                        unlock_kernel();
Robert Read's avatar
Robert Read committed
350 351 352
                        if ( error ) {
                                CERROR("presto_close: cannot journal close\n");
                                /* XXX these errors are really bad */
Linus Torvalds's avatar
Linus Torvalds committed
353
                                /* panic(); */
Robert Read's avatar
Robert Read committed
354 355 356 357
                                return;
                        }
                        fdata->fd_bytes_written = 0;
                }
Linus Torvalds's avatar
Linus Torvalds committed
358 359 360
        }
}

Robert Read's avatar
Robert Read committed
361 362
static ssize_t presto_file_write(struct file *file, const char *buf,
                                 size_t size, loff_t *off)
Linus Torvalds's avatar
Linus Torvalds committed
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
{
        struct rec_info rec;
        int error;
        struct presto_cache *cache;
        struct presto_file_set *fset;
        struct file_operations *fops;
        ssize_t res;
        int do_lml_here;
        void *handle = NULL;
        unsigned long blocks;
        struct presto_file_data *fdata;
        loff_t res_size; 

        error = presto_prep(file->f_dentry, &cache, &fset);
        if ( error ) {
                EXIT;
                return error;
        }

        blocks = (size >> file->f_dentry->d_inode->i_sb->s_blocksize_bits) + 1;
        /* XXX 3 is for ext2 indirect blocks ... */ 
        res_size = 2 * PRESTO_REQHIGH + ((blocks+3) 
                << file->f_dentry->d_inode->i_sb->s_blocksize_bits);

        error = presto_reserve_space(fset->fset_cache, res_size); 
Robert Read's avatar
Robert Read committed
388
        CDEBUG(D_INODE, "Reserved %Ld for %d\n", res_size, size); 
Linus Torvalds's avatar
Linus Torvalds committed
389 390 391 392 393
        if ( error ) { 
                EXIT;
                return -ENOSPC;
        }

Robert Read's avatar
Robert Read committed
394 395
        CDEBUG(D_INODE, "islento %d, minor: %d\n", 
               ISLENTO(cache->cache_psdev->uc_minor),
Linus Torvalds's avatar
Linus Torvalds committed
396
               cache->cache_psdev->uc_minor); 
Robert Read's avatar
Robert Read committed
397 398 399 400 401

        /* 
         *  XXX this lock should become a per inode lock when 
         *  Vinny's changes are in; we could just use i_sem.
         */
Linus Torvalds's avatar
Linus Torvalds committed
402 403
        read_lock(&fset->fset_lml.fd_lock); 
        fdata = (struct presto_file_data *)file->private_data;
Robert Read's avatar
Robert Read committed
404 405
        do_lml_here = size && (fdata->fd_do_lml == 0) &&
                !presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL);
Linus Torvalds's avatar
Linus Torvalds committed
406 407 408 409 410

        if (do_lml_here)
                fdata->fd_do_lml = 1;
        read_unlock(&fset->fset_lml.fd_lock); 

Robert Read's avatar
Robert Read committed
411 412 413 414 415
        /* XXX 
           There might be a bug here.  We need to make 
           absolutely sure that the ext3_file_write commits 
           after our transaction that writes the LML record.
           Nesting the file write helps if new blocks are allocated. 
Linus Torvalds's avatar
Linus Torvalds committed
416 417 418
        */
        res = 0;
        if (do_lml_here) {
Robert Read's avatar
Robert Read committed
419
                struct presto_version file_version;
Linus Torvalds's avatar
Linus Torvalds committed
420 421
                /* handle different space reqs from file system below! */
                handle = presto_trans_start(fset, file->f_dentry->d_inode, 
Robert Read's avatar
Robert Read committed
422
                                            KML_OPCODE_WRITE);
Linus Torvalds's avatar
Linus Torvalds committed
423 424
                if ( IS_ERR(handle) ) {
                        presto_release_space(fset->fset_cache, res_size); 
Robert Read's avatar
Robert Read committed
425
                        CERROR("presto_write: no space for transaction\n");
Linus Torvalds's avatar
Linus Torvalds committed
426 427
                        return -ENOSPC;
                }
Robert Read's avatar
Robert Read committed
428 429 430 431 432 433 434

                presto_getversion(&file_version, file->f_dentry->d_inode); 
                res = presto_write_lml_close(&rec, fset, file, 
                                             fdata->fd_info.remote_ino, 
                                             fdata->fd_info.remote_generation, 
                                             &fdata->fd_info.remote_version, 
                                             &file_version);
Linus Torvalds's avatar
Linus Torvalds committed
435 436
                fdata->fd_lml_offset = rec.offset;
                if ( res ) {
Robert Read's avatar
Robert Read committed
437 438
                        CERROR("intermezzo: PANIC failed to write LML\n");
                        *(int *)0 = 1;
Linus Torvalds's avatar
Linus Torvalds committed
439 440 441 442 443 444 445 446 447
                        EXIT;
                        goto exit_write;
                }
                presto_trans_commit(fset, handle);
        }

        fops = filter_c2cffops(cache->cache_filter);
        res = fops->write(file, buf, size, off);
        if ( res != size ) {
Robert Read's avatar
Robert Read committed
448
                CDEBUG(D_FILE, "file write returns short write: size %d, res %d\n", size, res); 
Linus Torvalds's avatar
Linus Torvalds committed
449 450 451 452
        }

        if ( (res > 0) && fdata ) 
                 presto_apply_write_policy(file, fset, res);
Robert Read's avatar
Robert Read committed
453

Linus Torvalds's avatar
Linus Torvalds committed
454 455 456 457 458 459
 exit_write:
        presto_release_space(fset->fset_cache, res_size); 
        return res;
}

struct file_operations presto_file_fops = {
Robert Read's avatar
Robert Read committed
460 461 462 463
        .write   = presto_file_write,
        .open    = presto_file_open,
        .release = presto_file_release,
        .ioctl   = presto_ioctl
Linus Torvalds's avatar
Linus Torvalds committed
464 465 466
};

struct inode_operations presto_file_iops = {
Robert Read's avatar
Robert Read committed
467 468
        .permission   = presto_permission,
        .setattr      = presto_setattr,
Linus Torvalds's avatar
Linus Torvalds committed
469
#ifdef CONFIG_FS_EXT_ATTR
Robert Read's avatar
Robert Read committed
470
        .set_ext_attr = presto_set_ext_attr,
Linus Torvalds's avatar
Linus Torvalds committed
471 472 473
#endif
};

Robert Read's avatar
Robert Read committed
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
/* FIXME: I bet we want to add a lock here and in presto_file_open. */
int izo_purge_file(struct presto_file_set *fset, char *file)
{
#if 0
        void *handle = NULL;
        char *path = NULL;
        struct nameidata nd;
        struct dentry *dentry;
        int rc = 0, len;
        loff_t oldsize;

        /* FIXME: not mtpt it's gone */
        len = strlen(fset->fset_cache->cache_mtpt) + strlen(file) + 1;
        PRESTO_ALLOC(path, len + 1);
        if (path == NULL)
                return -1;

        sprintf(path, "%s/%s", fset->fset_cache->cache_mtpt, file);
        rc = izo_lookup_file(fset, path, &nd);
        if (rc)
                goto error;
        dentry = nd.dentry;

        /* FIXME: take a lock here */

        if (dentry->d_inode->i_atime > CURRENT_TIME - 5) {
                /* We lost the race; this file was accessed while we were doing
                 * ioctls and lookups and whatnot. */
                rc = -EBUSY;
                goto error_unlock;
        }

        /* FIXME: Check if this file is open. */

        handle = presto_trans_start(fset, dentry->d_inode, KML_OPCODE_TRUNC);
        if (IS_ERR(handle)) {
                rc = -ENOMEM;
                goto error_unlock;
        }

        /* FIXME: Write LML record */
Linus Torvalds's avatar
Linus Torvalds committed
515

Robert Read's avatar
Robert Read committed
516 517 518 519 520 521 522
        oldsize = dentry->d_inode->i_size;
        rc = izo_do_truncate(fset, dentry, 0, oldsize);
        if (rc != 0)
                goto error_clear;
        rc = izo_do_truncate(fset, dentry, oldsize, 0);
        if (rc != 0)
                goto error_clear;
Linus Torvalds's avatar
Linus Torvalds committed
523

Robert Read's avatar
Robert Read committed
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
 error_clear:
        /* FIXME: clear LML record */

 error_unlock:
        /* FIXME: release the lock here */

 error:
        if (handle != NULL && !IS_ERR(handle))
                presto_trans_commit(fset, handle);
        if (path != NULL)
                PRESTO_FREE(path, len + 1);
        return rc;
#else
        return 0;
#endif
}