linux/fs/nilfs2/cpfile.c
<<
>>
Prefs
   1/*
   2 * cpfile.c - NILFS checkpoint file.
   3 *
   4 * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * Written by Koji Sato.
  17 */
  18
  19#include <linux/kernel.h>
  20#include <linux/fs.h>
  21#include <linux/string.h>
  22#include <linux/buffer_head.h>
  23#include <linux/errno.h>
  24#include "mdt.h"
  25#include "cpfile.h"
  26
  27
  28static inline unsigned long
  29nilfs_cpfile_checkpoints_per_block(const struct inode *cpfile)
  30{
  31        return NILFS_MDT(cpfile)->mi_entries_per_block;
  32}
  33
  34/* block number from the beginning of the file */
  35static unsigned long
  36nilfs_cpfile_get_blkoff(const struct inode *cpfile, __u64 cno)
  37{
  38        __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
  39
  40        do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
  41        return (unsigned long)tcno;
  42}
  43
  44/* offset in block */
  45static unsigned long
  46nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno)
  47{
  48        __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
  49
  50        return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
  51}
  52
  53static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile,
  54                                                    unsigned long blkoff)
  55{
  56        return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff
  57                + 1 - NILFS_MDT(cpfile)->mi_first_entry_offset;
  58}
  59
  60static unsigned long
  61nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile,
  62                                  __u64 curr,
  63                                  __u64 max)
  64{
  65        return min_t(__u64,
  66                     nilfs_cpfile_checkpoints_per_block(cpfile) -
  67                     nilfs_cpfile_get_offset(cpfile, curr),
  68                     max - curr);
  69}
  70
  71static inline int nilfs_cpfile_is_in_first(const struct inode *cpfile,
  72                                           __u64 cno)
  73{
  74        return nilfs_cpfile_get_blkoff(cpfile, cno) == 0;
  75}
  76
  77static unsigned int
  78nilfs_cpfile_block_add_valid_checkpoints(const struct inode *cpfile,
  79                                         struct buffer_head *bh,
  80                                         void *kaddr,
  81                                         unsigned int n)
  82{
  83        struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
  84        unsigned int count;
  85
  86        count = le32_to_cpu(cp->cp_checkpoints_count) + n;
  87        cp->cp_checkpoints_count = cpu_to_le32(count);
  88        return count;
  89}
  90
  91static unsigned int
  92nilfs_cpfile_block_sub_valid_checkpoints(const struct inode *cpfile,
  93                                         struct buffer_head *bh,
  94                                         void *kaddr,
  95                                         unsigned int n)
  96{
  97        struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
  98        unsigned int count;
  99
 100        WARN_ON(le32_to_cpu(cp->cp_checkpoints_count) < n);
 101        count = le32_to_cpu(cp->cp_checkpoints_count) - n;
 102        cp->cp_checkpoints_count = cpu_to_le32(count);
 103        return count;
 104}
 105
 106static inline struct nilfs_cpfile_header *
 107nilfs_cpfile_block_get_header(const struct inode *cpfile,
 108                              struct buffer_head *bh,
 109                              void *kaddr)
 110{
 111        return kaddr + bh_offset(bh);
 112}
 113
 114static struct nilfs_checkpoint *
 115nilfs_cpfile_block_get_checkpoint(const struct inode *cpfile, __u64 cno,
 116                                  struct buffer_head *bh,
 117                                  void *kaddr)
 118{
 119        return kaddr + bh_offset(bh) + nilfs_cpfile_get_offset(cpfile, cno) *
 120                NILFS_MDT(cpfile)->mi_entry_size;
 121}
 122
 123static void nilfs_cpfile_block_init(struct inode *cpfile,
 124                                    struct buffer_head *bh,
 125                                    void *kaddr)
 126{
 127        struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
 128        size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
 129        int n = nilfs_cpfile_checkpoints_per_block(cpfile);
 130
 131        while (n-- > 0) {
 132                nilfs_checkpoint_set_invalid(cp);
 133                cp = (void *)cp + cpsz;
 134        }
 135}
 136
 137static inline int nilfs_cpfile_get_header_block(struct inode *cpfile,
 138                                                struct buffer_head **bhp)
 139{
 140        return nilfs_mdt_get_block(cpfile, 0, 0, NULL, bhp);
 141}
 142
 143static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile,
 144                                                    __u64 cno,
 145                                                    int create,
 146                                                    struct buffer_head **bhp)
 147{
 148        return nilfs_mdt_get_block(cpfile,
 149                                   nilfs_cpfile_get_blkoff(cpfile, cno),
 150                                   create, nilfs_cpfile_block_init, bhp);
 151}
 152
 153/**
 154 * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile
 155 * @cpfile: inode of cpfile
 156 * @start_cno: start checkpoint number (inclusive)
 157 * @end_cno: end checkpoint number (inclusive)
 158 * @cnop: place to store the next checkpoint number
 159 * @bhp: place to store a pointer to buffer_head struct
 160 *
 161 * Return Value: On success, it returns 0. On error, the following negative
 162 * error code is returned.
 163 *
 164 * %-ENOMEM - Insufficient memory available.
 165 *
 166 * %-EIO - I/O error
 167 *
 168 * %-ENOENT - no block exists in the range.
 169 */
 170static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile,
 171                                              __u64 start_cno, __u64 end_cno,
 172                                              __u64 *cnop,
 173                                              struct buffer_head **bhp)
 174{
 175        unsigned long start, end, blkoff;
 176        int ret;
 177
 178        if (unlikely(start_cno > end_cno))
 179                return -ENOENT;
 180
 181        start = nilfs_cpfile_get_blkoff(cpfile, start_cno);
 182        end = nilfs_cpfile_get_blkoff(cpfile, end_cno);
 183
 184        ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp);
 185        if (!ret)
 186                *cnop = (blkoff == start) ? start_cno :
 187                        nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff);
 188        return ret;
 189}
 190
 191static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile,
 192                                                       __u64 cno)
 193{
 194        return nilfs_mdt_delete_block(cpfile,
 195                                      nilfs_cpfile_get_blkoff(cpfile, cno));
 196}
 197
 198/**
 199 * nilfs_cpfile_get_checkpoint - get a checkpoint
 200 * @cpfile: inode of checkpoint file
 201 * @cno: checkpoint number
 202 * @create: create flag
 203 * @cpp: pointer to a checkpoint
 204 * @bhp: pointer to a buffer head
 205 *
 206 * Description: nilfs_cpfile_get_checkpoint() acquires the checkpoint
 207 * specified by @cno. A new checkpoint will be created if @cno is the current
 208 * checkpoint number and @create is nonzero.
 209 *
 210 * Return Value: On success, 0 is returned, and the checkpoint and the
 211 * buffer head of the buffer on which the checkpoint is located are stored in
 212 * the place pointed by @cpp and @bhp, respectively. On error, one of the
 213 * following negative error codes is returned.
 214 *
 215 * %-EIO - I/O error.
 216 *
 217 * %-ENOMEM - Insufficient amount of memory available.
 218 *
 219 * %-ENOENT - No such checkpoint.
 220 *
 221 * %-EINVAL - invalid checkpoint.
 222 */
 223int nilfs_cpfile_get_checkpoint(struct inode *cpfile,
 224                                __u64 cno,
 225                                int create,
 226                                struct nilfs_checkpoint **cpp,
 227                                struct buffer_head **bhp)
 228{
 229        struct buffer_head *header_bh, *cp_bh;
 230        struct nilfs_cpfile_header *header;
 231        struct nilfs_checkpoint *cp;
 232        void *kaddr;
 233        int ret;
 234
 235        if (unlikely(cno < 1 || cno > nilfs_mdt_cno(cpfile) ||
 236                     (cno < nilfs_mdt_cno(cpfile) && create)))
 237                return -EINVAL;
 238
 239        down_write(&NILFS_MDT(cpfile)->mi_sem);
 240
 241        ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
 242        if (ret < 0)
 243                goto out_sem;
 244        ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, create, &cp_bh);
 245        if (ret < 0)
 246                goto out_header;
 247        kaddr = kmap(cp_bh->b_page);
 248        cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
 249        if (nilfs_checkpoint_invalid(cp)) {
 250                if (!create) {
 251                        kunmap(cp_bh->b_page);
 252                        brelse(cp_bh);
 253                        ret = -ENOENT;
 254                        goto out_header;
 255                }
 256                /* a newly-created checkpoint */
 257                nilfs_checkpoint_clear_invalid(cp);
 258                if (!nilfs_cpfile_is_in_first(cpfile, cno))
 259                        nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,
 260                                                                 kaddr, 1);
 261                mark_buffer_dirty(cp_bh);
 262
 263                kaddr = kmap_atomic(header_bh->b_page);
 264                header = nilfs_cpfile_block_get_header(cpfile, header_bh,
 265                                                       kaddr);
 266                le64_add_cpu(&header->ch_ncheckpoints, 1);
 267                kunmap_atomic(kaddr);
 268                mark_buffer_dirty(header_bh);
 269                nilfs_mdt_mark_dirty(cpfile);
 270        }
 271
 272        if (cpp != NULL)
 273                *cpp = cp;
 274        *bhp = cp_bh;
 275
 276 out_header:
 277        brelse(header_bh);
 278
 279 out_sem:
 280        up_write(&NILFS_MDT(cpfile)->mi_sem);
 281        return ret;
 282}
 283
 284/**
 285 * nilfs_cpfile_put_checkpoint - put a checkpoint
 286 * @cpfile: inode of checkpoint file
 287 * @cno: checkpoint number
 288 * @bh: buffer head
 289 *
 290 * Description: nilfs_cpfile_put_checkpoint() releases the checkpoint
 291 * specified by @cno. @bh must be the buffer head which has been returned by
 292 * a previous call to nilfs_cpfile_get_checkpoint() with @cno.
 293 */
 294void nilfs_cpfile_put_checkpoint(struct inode *cpfile, __u64 cno,
 295                                 struct buffer_head *bh)
 296{
 297        kunmap(bh->b_page);
 298        brelse(bh);
 299}
 300
 301/**
 302 * nilfs_cpfile_delete_checkpoints - delete checkpoints
 303 * @cpfile: inode of checkpoint file
 304 * @start: start checkpoint number
 305 * @end: end checkpoint numer
 306 *
 307 * Description: nilfs_cpfile_delete_checkpoints() deletes the checkpoints in
 308 * the period from @start to @end, excluding @end itself. The checkpoints
 309 * which have been already deleted are ignored.
 310 *
 311 * Return Value: On success, 0 is returned. On error, one of the following
 312 * negative error codes is returned.
 313 *
 314 * %-EIO - I/O error.
 315 *
 316 * %-ENOMEM - Insufficient amount of memory available.
 317 *
 318 * %-EINVAL - invalid checkpoints.
 319 */
 320int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
 321                                    __u64 start,
 322                                    __u64 end)
 323{
 324        struct buffer_head *header_bh, *cp_bh;
 325        struct nilfs_cpfile_header *header;
 326        struct nilfs_checkpoint *cp;
 327        size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
 328        __u64 cno;
 329        void *kaddr;
 330        unsigned long tnicps;
 331        int ret, ncps, nicps, nss, count, i;
 332
 333        if (unlikely(start == 0 || start > end)) {
 334                nilfs_msg(cpfile->i_sb, KERN_ERR,
 335                          "cannot delete checkpoints: invalid range [%llu, %llu)",
 336                          (unsigned long long)start, (unsigned long long)end);
 337                return -EINVAL;
 338        }
 339
 340        down_write(&NILFS_MDT(cpfile)->mi_sem);
 341
 342        ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
 343        if (ret < 0)
 344                goto out_sem;
 345        tnicps = 0;
 346        nss = 0;
 347
 348        for (cno = start; cno < end; cno += ncps) {
 349                ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end);
 350                ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
 351                if (ret < 0) {
 352                        if (ret != -ENOENT)
 353                                break;
 354                        /* skip hole */
 355                        ret = 0;
 356                        continue;
 357                }
 358
 359                kaddr = kmap_atomic(cp_bh->b_page);
 360                cp = nilfs_cpfile_block_get_checkpoint(
 361                        cpfile, cno, cp_bh, kaddr);
 362                nicps = 0;
 363                for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) {
 364                        if (nilfs_checkpoint_snapshot(cp)) {
 365                                nss++;
 366                        } else if (!nilfs_checkpoint_invalid(cp)) {
 367                                nilfs_checkpoint_set_invalid(cp);
 368                                nicps++;
 369                        }
 370                }
 371                if (nicps > 0) {
 372                        tnicps += nicps;
 373                        mark_buffer_dirty(cp_bh);
 374                        nilfs_mdt_mark_dirty(cpfile);
 375                        if (!nilfs_cpfile_is_in_first(cpfile, cno)) {
 376                                count =
 377                                  nilfs_cpfile_block_sub_valid_checkpoints(
 378                                                cpfile, cp_bh, kaddr, nicps);
 379                                if (count == 0) {
 380                                        /* make hole */
 381                                        kunmap_atomic(kaddr);
 382                                        brelse(cp_bh);
 383                                        ret =
 384                                          nilfs_cpfile_delete_checkpoint_block(
 385                                                                   cpfile, cno);
 386                                        if (ret == 0)
 387                                                continue;
 388                                        nilfs_msg(cpfile->i_sb, KERN_ERR,
 389                                                  "error %d deleting checkpoint block",
 390                                                  ret);
 391                                        break;
 392                                }
 393                        }
 394                }
 395
 396                kunmap_atomic(kaddr);
 397                brelse(cp_bh);
 398        }
 399
 400        if (tnicps > 0) {
 401                kaddr = kmap_atomic(header_bh->b_page);
 402                header = nilfs_cpfile_block_get_header(cpfile, header_bh,
 403                                                       kaddr);
 404                le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps);
 405                mark_buffer_dirty(header_bh);
 406                nilfs_mdt_mark_dirty(cpfile);
 407                kunmap_atomic(kaddr);
 408        }
 409
 410        brelse(header_bh);
 411        if (nss > 0)
 412                ret = -EBUSY;
 413
 414 out_sem:
 415        up_write(&NILFS_MDT(cpfile)->mi_sem);
 416        return ret;
 417}
 418
 419static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,
 420                                              struct nilfs_checkpoint *cp,
 421                                              struct nilfs_cpinfo *ci)
 422{
 423        ci->ci_flags = le32_to_cpu(cp->cp_flags);
 424        ci->ci_cno = le64_to_cpu(cp->cp_cno);
 425        ci->ci_create = le64_to_cpu(cp->cp_create);
 426        ci->ci_nblk_inc = le64_to_cpu(cp->cp_nblk_inc);
 427        ci->ci_inodes_count = le64_to_cpu(cp->cp_inodes_count);
 428        ci->ci_blocks_count = le64_to_cpu(cp->cp_blocks_count);
 429        ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
 430}
 431
 432static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
 433                                          void *buf, unsigned int cisz,
 434                                          size_t nci)
 435{
 436        struct nilfs_checkpoint *cp;
 437        struct nilfs_cpinfo *ci = buf;
 438        struct buffer_head *bh;
 439        size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
 440        __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;
 441        void *kaddr;
 442        int n, ret;
 443        int ncps, i;
 444
 445        if (cno == 0)
 446                return -ENOENT; /* checkpoint number 0 is invalid */
 447        down_read(&NILFS_MDT(cpfile)->mi_sem);
 448
 449        for (n = 0; n < nci; cno += ncps) {
 450                ret = nilfs_cpfile_find_checkpoint_block(
 451                        cpfile, cno, cur_cno - 1, &cno, &bh);
 452                if (ret < 0) {
 453                        if (likely(ret == -ENOENT))
 454                                break;
 455                        goto out;
 456                }
 457                ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno);
 458
 459                kaddr = kmap_atomic(bh->b_page);
 460                cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
 461                for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) {
 462                        if (!nilfs_checkpoint_invalid(cp)) {
 463                                nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp,
 464                                                                  ci);
 465                                ci = (void *)ci + cisz;
 466                                n++;
 467                        }
 468                }
 469                kunmap_atomic(kaddr);
 470                brelse(bh);
 471        }
 472
 473        ret = n;
 474        if (n > 0) {
 475                ci = (void *)ci - cisz;
 476                *cnop = ci->ci_cno + 1;
 477        }
 478
 479 out:
 480        up_read(&NILFS_MDT(cpfile)->mi_sem);
 481        return ret;
 482}
 483
 484static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
 485                                          void *buf, unsigned int cisz,
 486                                          size_t nci)
 487{
 488        struct buffer_head *bh;
 489        struct nilfs_cpfile_header *header;
 490        struct nilfs_checkpoint *cp;
 491        struct nilfs_cpinfo *ci = buf;
 492        __u64 curr = *cnop, next;
 493        unsigned long curr_blkoff, next_blkoff;
 494        void *kaddr;
 495        int n = 0, ret;
 496
 497        down_read(&NILFS_MDT(cpfile)->mi_sem);
 498
 499        if (curr == 0) {
 500                ret = nilfs_cpfile_get_header_block(cpfile, &bh);
 501                if (ret < 0)
 502                        goto out;
 503                kaddr = kmap_atomic(bh->b_page);
 504                header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
 505                curr = le64_to_cpu(header->ch_snapshot_list.ssl_next);
 506                kunmap_atomic(kaddr);
 507                brelse(bh);
 508                if (curr == 0) {
 509                        ret = 0;
 510                        goto out;
 511                }
 512        } else if (unlikely(curr == ~(__u64)0)) {
 513                ret = 0;
 514                goto out;
 515        }
 516
 517        curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr);
 518        ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh);
 519        if (unlikely(ret < 0)) {
 520                if (ret == -ENOENT)
 521                        ret = 0; /* No snapshots (started from a hole block) */
 522                goto out;
 523        }
 524        kaddr = kmap_atomic(bh->b_page);
 525        while (n < nci) {
 526                cp = nilfs_cpfile_block_get_checkpoint(cpfile, curr, bh, kaddr);
 527                curr = ~(__u64)0; /* Terminator */
 528                if (unlikely(nilfs_checkpoint_invalid(cp) ||
 529                             !nilfs_checkpoint_snapshot(cp)))
 530                        break;
 531                nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci);
 532                ci = (void *)ci + cisz;
 533                n++;
 534                next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
 535                if (next == 0)
 536                        break; /* reach end of the snapshot list */
 537
 538                next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next);
 539                if (curr_blkoff != next_blkoff) {
 540                        kunmap_atomic(kaddr);
 541                        brelse(bh);
 542                        ret = nilfs_cpfile_get_checkpoint_block(cpfile, next,
 543                                                                0, &bh);
 544                        if (unlikely(ret < 0)) {
 545                                WARN_ON(ret == -ENOENT);
 546                                goto out;
 547                        }
 548                        kaddr = kmap_atomic(bh->b_page);
 549                }
 550                curr = next;
 551                curr_blkoff = next_blkoff;
 552        }
 553        kunmap_atomic(kaddr);
 554        brelse(bh);
 555        *cnop = curr;
 556        ret = n;
 557
 558 out:
 559        up_read(&NILFS_MDT(cpfile)->mi_sem);
 560        return ret;
 561}
 562
 563/**
 564 * nilfs_cpfile_get_cpinfo -
 565 * @cpfile:
 566 * @cno:
 567 * @ci:
 568 * @nci:
 569 */
 570
 571ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
 572                                void *buf, unsigned int cisz, size_t nci)
 573{
 574        switch (mode) {
 575        case NILFS_CHECKPOINT:
 576                return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci);
 577        case NILFS_SNAPSHOT:
 578                return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci);
 579        default:
 580                return -EINVAL;
 581        }
 582}
 583
 584/**
 585 * nilfs_cpfile_delete_checkpoint -
 586 * @cpfile:
 587 * @cno:
 588 */
 589int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)
 590{
 591        struct nilfs_cpinfo ci;
 592        __u64 tcno = cno;
 593        ssize_t nci;
 594
 595        nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1);
 596        if (nci < 0)
 597                return nci;
 598        else if (nci == 0 || ci.ci_cno != cno)
 599                return -ENOENT;
 600        else if (nilfs_cpinfo_snapshot(&ci))
 601                return -EBUSY;
 602
 603        return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1);
 604}
 605
 606static struct nilfs_snapshot_list *
 607nilfs_cpfile_block_get_snapshot_list(const struct inode *cpfile,
 608                                     __u64 cno,
 609                                     struct buffer_head *bh,
 610                                     void *kaddr)
 611{
 612        struct nilfs_cpfile_header *header;
 613        struct nilfs_checkpoint *cp;
 614        struct nilfs_snapshot_list *list;
 615
 616        if (cno != 0) {
 617                cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
 618                list = &cp->cp_snapshot_list;
 619        } else {
 620                header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
 621                list = &header->ch_snapshot_list;
 622        }
 623        return list;
 624}
 625
 626static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
 627{
 628        struct buffer_head *header_bh, *curr_bh, *prev_bh, *cp_bh;
 629        struct nilfs_cpfile_header *header;
 630        struct nilfs_checkpoint *cp;
 631        struct nilfs_snapshot_list *list;
 632        __u64 curr, prev;
 633        unsigned long curr_blkoff, prev_blkoff;
 634        void *kaddr;
 635        int ret;
 636
 637        if (cno == 0)
 638                return -ENOENT; /* checkpoint number 0 is invalid */
 639        down_write(&NILFS_MDT(cpfile)->mi_sem);
 640
 641        ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
 642        if (ret < 0)
 643                goto out_sem;
 644        kaddr = kmap_atomic(cp_bh->b_page);
 645        cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
 646        if (nilfs_checkpoint_invalid(cp)) {
 647                ret = -ENOENT;
 648                kunmap_atomic(kaddr);
 649                goto out_cp;
 650        }
 651        if (nilfs_checkpoint_snapshot(cp)) {
 652                ret = 0;
 653                kunmap_atomic(kaddr);
 654                goto out_cp;
 655        }
 656        kunmap_atomic(kaddr);
 657
 658        ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
 659        if (ret < 0)
 660                goto out_cp;
 661        kaddr = kmap_atomic(header_bh->b_page);
 662        header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
 663        list = &header->ch_snapshot_list;
 664        curr_bh = header_bh;
 665        get_bh(curr_bh);
 666        curr = 0;
 667        curr_blkoff = 0;
 668        prev = le64_to_cpu(list->ssl_prev);
 669        while (prev > cno) {
 670                prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev);
 671                curr = prev;
 672                if (curr_blkoff != prev_blkoff) {
 673                        kunmap_atomic(kaddr);
 674                        brelse(curr_bh);
 675                        ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr,
 676                                                                0, &curr_bh);
 677                        if (ret < 0)
 678                                goto out_header;
 679                        kaddr = kmap_atomic(curr_bh->b_page);
 680                }
 681                curr_blkoff = prev_blkoff;
 682                cp = nilfs_cpfile_block_get_checkpoint(
 683                        cpfile, curr, curr_bh, kaddr);
 684                list = &cp->cp_snapshot_list;
 685                prev = le64_to_cpu(list->ssl_prev);
 686        }
 687        kunmap_atomic(kaddr);
 688
 689        if (prev != 0) {
 690                ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
 691                                                        &prev_bh);
 692                if (ret < 0)
 693                        goto out_curr;
 694        } else {
 695                prev_bh = header_bh;
 696                get_bh(prev_bh);
 697        }
 698
 699        kaddr = kmap_atomic(curr_bh->b_page);
 700        list = nilfs_cpfile_block_get_snapshot_list(
 701                cpfile, curr, curr_bh, kaddr);
 702        list->ssl_prev = cpu_to_le64(cno);
 703        kunmap_atomic(kaddr);
 704
 705        kaddr = kmap_atomic(cp_bh->b_page);
 706        cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
 707        cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr);
 708        cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev);
 709        nilfs_checkpoint_set_snapshot(cp);
 710        kunmap_atomic(kaddr);
 711
 712        kaddr = kmap_atomic(prev_bh->b_page);
 713        list = nilfs_cpfile_block_get_snapshot_list(
 714                cpfile, prev, prev_bh, kaddr);
 715        list->ssl_next = cpu_to_le64(cno);
 716        kunmap_atomic(kaddr);
 717
 718        kaddr = kmap_atomic(header_bh->b_page);
 719        header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
 720        le64_add_cpu(&header->ch_nsnapshots, 1);
 721        kunmap_atomic(kaddr);
 722
 723        mark_buffer_dirty(prev_bh);
 724        mark_buffer_dirty(curr_bh);
 725        mark_buffer_dirty(cp_bh);
 726        mark_buffer_dirty(header_bh);
 727        nilfs_mdt_mark_dirty(cpfile);
 728
 729        brelse(prev_bh);
 730
 731 out_curr:
 732        brelse(curr_bh);
 733
 734 out_header:
 735        brelse(header_bh);
 736
 737 out_cp:
 738        brelse(cp_bh);
 739
 740 out_sem:
 741        up_write(&NILFS_MDT(cpfile)->mi_sem);
 742        return ret;
 743}
 744
 745static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
 746{
 747        struct buffer_head *header_bh, *next_bh, *prev_bh, *cp_bh;
 748        struct nilfs_cpfile_header *header;
 749        struct nilfs_checkpoint *cp;
 750        struct nilfs_snapshot_list *list;
 751        __u64 next, prev;
 752        void *kaddr;
 753        int ret;
 754
 755        if (cno == 0)
 756                return -ENOENT; /* checkpoint number 0 is invalid */
 757        down_write(&NILFS_MDT(cpfile)->mi_sem);
 758
 759        ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
 760        if (ret < 0)
 761                goto out_sem;
 762        kaddr = kmap_atomic(cp_bh->b_page);
 763        cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
 764        if (nilfs_checkpoint_invalid(cp)) {
 765                ret = -ENOENT;
 766                kunmap_atomic(kaddr);
 767                goto out_cp;
 768        }
 769        if (!nilfs_checkpoint_snapshot(cp)) {
 770                ret = 0;
 771                kunmap_atomic(kaddr);
 772                goto out_cp;
 773        }
 774
 775        list = &cp->cp_snapshot_list;
 776        next = le64_to_cpu(list->ssl_next);
 777        prev = le64_to_cpu(list->ssl_prev);
 778        kunmap_atomic(kaddr);
 779
 780        ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
 781        if (ret < 0)
 782                goto out_cp;
 783        if (next != 0) {
 784                ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0,
 785                                                        &next_bh);
 786                if (ret < 0)
 787                        goto out_header;
 788        } else {
 789                next_bh = header_bh;
 790                get_bh(next_bh);
 791        }
 792        if (prev != 0) {
 793                ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
 794                                                        &prev_bh);
 795                if (ret < 0)
 796                        goto out_next;
 797        } else {
 798                prev_bh = header_bh;
 799                get_bh(prev_bh);
 800        }
 801
 802        kaddr = kmap_atomic(next_bh->b_page);
 803        list = nilfs_cpfile_block_get_snapshot_list(
 804                cpfile, next, next_bh, kaddr);
 805        list->ssl_prev = cpu_to_le64(prev);
 806        kunmap_atomic(kaddr);
 807
 808        kaddr = kmap_atomic(prev_bh->b_page);
 809        list = nilfs_cpfile_block_get_snapshot_list(
 810                cpfile, prev, prev_bh, kaddr);
 811        list->ssl_next = cpu_to_le64(next);
 812        kunmap_atomic(kaddr);
 813
 814        kaddr = kmap_atomic(cp_bh->b_page);
 815        cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
 816        cp->cp_snapshot_list.ssl_next = cpu_to_le64(0);
 817        cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0);
 818        nilfs_checkpoint_clear_snapshot(cp);
 819        kunmap_atomic(kaddr);
 820
 821        kaddr = kmap_atomic(header_bh->b_page);
 822        header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
 823        le64_add_cpu(&header->ch_nsnapshots, -1);
 824        kunmap_atomic(kaddr);
 825
 826        mark_buffer_dirty(next_bh);
 827        mark_buffer_dirty(prev_bh);
 828        mark_buffer_dirty(cp_bh);
 829        mark_buffer_dirty(header_bh);
 830        nilfs_mdt_mark_dirty(cpfile);
 831
 832        brelse(prev_bh);
 833
 834 out_next:
 835        brelse(next_bh);
 836
 837 out_header:
 838        brelse(header_bh);
 839
 840 out_cp:
 841        brelse(cp_bh);
 842
 843 out_sem:
 844        up_write(&NILFS_MDT(cpfile)->mi_sem);
 845        return ret;
 846}
 847
 848/**
 849 * nilfs_cpfile_is_snapshot -
 850 * @cpfile: inode of checkpoint file
 851 * @cno: checkpoint number
 852 *
 853 * Description:
 854 *
 855 * Return Value: On success, 1 is returned if the checkpoint specified by
 856 * @cno is a snapshot, or 0 if not. On error, one of the following negative
 857 * error codes is returned.
 858 *
 859 * %-EIO - I/O error.
 860 *
 861 * %-ENOMEM - Insufficient amount of memory available.
 862 *
 863 * %-ENOENT - No such checkpoint.
 864 */
 865int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno)
 866{
 867        struct buffer_head *bh;
 868        struct nilfs_checkpoint *cp;
 869        void *kaddr;
 870        int ret;
 871
 872        /*
 873         * CP number is invalid if it's zero or larger than the
 874         * largest existing one.
 875         */
 876        if (cno == 0 || cno >= nilfs_mdt_cno(cpfile))
 877                return -ENOENT;
 878        down_read(&NILFS_MDT(cpfile)->mi_sem);
 879
 880        ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);
 881        if (ret < 0)
 882                goto out;
 883        kaddr = kmap_atomic(bh->b_page);
 884        cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
 885        if (nilfs_checkpoint_invalid(cp))
 886                ret = -ENOENT;
 887        else
 888                ret = nilfs_checkpoint_snapshot(cp);
 889        kunmap_atomic(kaddr);
 890        brelse(bh);
 891
 892 out:
 893        up_read(&NILFS_MDT(cpfile)->mi_sem);
 894        return ret;
 895}
 896
 897/**
 898 * nilfs_cpfile_change_cpmode - change checkpoint mode
 899 * @cpfile: inode of checkpoint file
 900 * @cno: checkpoint number
 901 * @status: mode of checkpoint
 902 *
 903 * Description: nilfs_change_cpmode() changes the mode of the checkpoint
 904 * specified by @cno. The mode @mode is NILFS_CHECKPOINT or NILFS_SNAPSHOT.
 905 *
 906 * Return Value: On success, 0 is returned. On error, one of the following
 907 * negative error codes is returned.
 908 *
 909 * %-EIO - I/O error.
 910 *
 911 * %-ENOMEM - Insufficient amount of memory available.
 912 *
 913 * %-ENOENT - No such checkpoint.
 914 */
 915int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
 916{
 917        int ret;
 918
 919        switch (mode) {
 920        case NILFS_CHECKPOINT:
 921                if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno))
 922                        /*
 923                         * Current implementation does not have to protect
 924                         * plain read-only mounts since they are exclusive
 925                         * with a read/write mount and are protected from the
 926                         * cleaner.
 927                         */
 928                        ret = -EBUSY;
 929                else
 930                        ret = nilfs_cpfile_clear_snapshot(cpfile, cno);
 931                return ret;
 932        case NILFS_SNAPSHOT:
 933                return nilfs_cpfile_set_snapshot(cpfile, cno);
 934        default:
 935                return -EINVAL;
 936        }
 937}
 938
 939/**
 940 * nilfs_cpfile_get_stat - get checkpoint statistics
 941 * @cpfile: inode of checkpoint file
 942 * @stat: pointer to a structure of checkpoint statistics
 943 *
 944 * Description: nilfs_cpfile_get_stat() returns information about checkpoints.
 945 *
 946 * Return Value: On success, 0 is returned, and checkpoints information is
 947 * stored in the place pointed by @stat. On error, one of the following
 948 * negative error codes is returned.
 949 *
 950 * %-EIO - I/O error.
 951 *
 952 * %-ENOMEM - Insufficient amount of memory available.
 953 */
 954int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat)
 955{
 956        struct buffer_head *bh;
 957        struct nilfs_cpfile_header *header;
 958        void *kaddr;
 959        int ret;
 960
 961        down_read(&NILFS_MDT(cpfile)->mi_sem);
 962
 963        ret = nilfs_cpfile_get_header_block(cpfile, &bh);
 964        if (ret < 0)
 965                goto out_sem;
 966        kaddr = kmap_atomic(bh->b_page);
 967        header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
 968        cpstat->cs_cno = nilfs_mdt_cno(cpfile);
 969        cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints);
 970        cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots);
 971        kunmap_atomic(kaddr);
 972        brelse(bh);
 973
 974 out_sem:
 975        up_read(&NILFS_MDT(cpfile)->mi_sem);
 976        return ret;
 977}
 978
 979/**
 980 * nilfs_cpfile_read - read or get cpfile inode
 981 * @sb: super block instance
 982 * @cpsize: size of a checkpoint entry
 983 * @raw_inode: on-disk cpfile inode
 984 * @inodep: buffer to store the inode
 985 */
 986int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,
 987                      struct nilfs_inode *raw_inode, struct inode **inodep)
 988{
 989        struct inode *cpfile;
 990        int err;
 991
 992        if (cpsize > sb->s_blocksize) {
 993                nilfs_msg(sb, KERN_ERR,
 994                          "too large checkpoint size: %zu bytes", cpsize);
 995                return -EINVAL;
 996        } else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) {
 997                nilfs_msg(sb, KERN_ERR,
 998                          "too small checkpoint size: %zu bytes", cpsize);
 999                return -EINVAL;
1000        }
1001
1002        cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO);
1003        if (unlikely(!cpfile))
1004                return -ENOMEM;
1005        if (!(cpfile->i_state & I_NEW))
1006                goto out;
1007
1008        err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0);
1009        if (err)
1010                goto failed;
1011
1012        nilfs_mdt_set_entry_size(cpfile, cpsize,
1013                                 sizeof(struct nilfs_cpfile_header));
1014
1015        err = nilfs_read_inode_common(cpfile, raw_inode);
1016        if (err)
1017                goto failed;
1018
1019        unlock_new_inode(cpfile);
1020 out:
1021        *inodep = cpfile;
1022        return 0;
1023 failed:
1024        iget_failed(cpfile);
1025        return err;
1026}
1027