summaryrefslogtreecommitdiffstats
path: root/src/librbd/operation/ResizeRequest.h
blob: f5e2f807fde641b7429578f9af68eb8a8ce30637 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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
147
148
149
150
151
152
153
154
155
156
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
#ifndef CEPH_LIBRBD_OPERATION_RESIZE_REQUEST_H
#define CEPH_LIBRBD_OPERATION_RESIZE_REQUEST_H

#include "librbd/operation/Request.h"
#include "include/xlist.h"

namespace librbd
{

class ImageCtx;
class ProgressContext;

namespace operation {

template <typename ImageCtxT = ImageCtx>
class ResizeRequest : public Request<ImageCtxT> {
public:
  static ResizeRequest *create(ImageCtxT &image_ctx, Context *on_finish,
                               uint64_t new_size, bool allow_shrink,
                               ProgressContext &prog_ctx, uint64_t journal_op_tid,
                               bool disable_journal) {
    return new ResizeRequest(image_ctx, on_finish, new_size, allow_shrink, prog_ctx,
                             journal_op_tid, disable_journal);
  }

  ResizeRequest(ImageCtxT &image_ctx, Context *on_finish, uint64_t new_size,
                bool allow_shrink, ProgressContext &prog_ctx, uint64_t journal_op_tid,
                bool disable_journal);
  ~ResizeRequest() override;

  inline bool shrinking() const {
    return (m_shrink_size_visible && m_new_size < m_original_size);
  }

  inline uint64_t get_image_size() const {
    return m_new_size;
  }

  void send() override;

protected:
  void send_op() override;
  bool should_complete(int r) override {
    return true;
  }
  bool can_affect_io() const override {
    return true;
  }
  journal::Event create_event(uint64_t op_tid) const override {
    return journal::ResizeEvent(op_tid, m_new_size);
  }

private:
  /**
   * Resize goes through the following state machine to resize the image
   * and update the object map:
   *
   * @verbatim
   *
   * <start>
   *    |
   *    v
   * STATE_PRE_BLOCK_WRITES
   *    |
   *    v
   * STATE_APPEND_OP_EVENT (skip if journaling
   *    |                   disabled)
   *    |
   *    | (grow)
   *    |\--------> STATE_GROW_OBJECT_MAP (skip if object map
   *    |                 |                disabled)
   *    |                 v
   *    |           STATE_UPDATE_HEADER ----------------------------\
   *    |                                 (unblock writes)          |
   *    |                                                           |
   *    | (unblock writes)                                          |
   *    |                                                           |
   *    | (shrink)                                                  |
   *    |\--------> STATE_FLUSH_CACHE                               |
   *    |                 |                                         |
   *    |                 v                                         |
   *    |           STATE_INVALIDATE_CACHE                          |
   *    |                 |                                         |
   *    |                 v                                         |
   *    |           STATE_TRIM_IMAGE                                |
   *    |                 |                                         |
   *    |                 v                                         |
   *    |           STATE_POST_BLOCK_WRITES                         |
   *    |                 |                                         |
   *    |                 v                                         |
   *    |           STATE_UPDATE_HEADER                             |
   *    |                 |                                         |
   *    |                 v                                         |
   *    |           STATE_SHRINK_OBJECT_MAP (skip if object map     |
   *    |                 |                  disabled)              |
   *    |                 | (unblock writes)                        |
   *    | (no change)     v                                         |
   *    \------------> <finish> <-----------------------------------/
   *
   * @endverbatim
   *
   * The _OBJECT_MAP states are skipped if the object map isn't enabled.
   * The state machine will immediately transition to _FINISHED if there
   * are no objects to trim.
   */

  uint64_t m_original_size;
  uint64_t m_new_size;
  bool m_allow_shrink = true;
  ProgressContext &m_prog_ctx;
  uint64_t m_new_parent_overlap;
  bool m_shrink_size_visible = false;
  bool m_disable_journal = false;

  typename xlist<ResizeRequest<ImageCtxT>*>::item m_xlist_item;

  void send_pre_block_writes();
  Context *handle_pre_block_writes(int *result);

  Context *send_append_op_event();
  Context *handle_append_op_event(int *result);

  void send_flush_cache();
  Context *handle_flush_cache(int *result);

  void send_invalidate_cache();
  Context *handle_invalidate_cache(int *result);

  void send_trim_image();
  Context *handle_trim_image(int *result);

  Context *send_grow_object_map();
  Context *handle_grow_object_map(int *result);

  Context *send_shrink_object_map();
  Context *handle_shrink_object_map(int *result);

  void send_post_block_writes();
  Context *handle_post_block_writes(int *result);

  void send_update_header();
  Context *handle_update_header(int *result);

  void compute_parent_overlap();
  void update_size_and_overlap();

};

} // namespace operation
} // namespace librbd

extern template class librbd::operation::ResizeRequest<librbd::ImageCtx>;

#endif // CEPH_LIBRBD_OPERATION_RESIZE_REQUEST_H