// chenkl1995@gmail.com
// https://atcoder.jp/contests/dp/tasks
#include <bits/stdc++.h>
using namespace std;

using LL = long long;
using LD = long double;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
using VI = vector<int>;
using VVI = vector<vector<int>>;
template<class T> using V = vector<T>;
template<class T> using VV = vector<vector<T>>;
template<class T> inline void IN(T &x) {
	x = 0; T f = 1; char ch = getchar();
	while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
	while (isdigit(ch)) { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); }
	x *= f;
}
template<typename A, typename B> inline void IN(A &x, B &y) { IN(x); IN(y); }
template<typename A, typename B, typename C> inline void IN(A &x, B &y, C &z) { IN(x); IN(y); IN(z); }

#define FastI ios_base::sync_with_stdio(0), cin.tie(0);
#define FastIO ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define endl '\n'
#define REP(i, l, r) for (auto i = (l); i <= (r); ++i)
#define PER(i, l, r) for (auto i = (l); i >= (r); --i)
#define FOR(i, l, r) for (auto i = (l); i < (r); ++i)
#define ROF(i, l, r) for (auto i = (l); i > (r); --i)
#define FORN(i, n) for (auto i = 0; i < (n); ++i)
#define REPN(i, n) for (auto i = 1; i <= (n); ++i)
#define FORA(i, a) for (auto &i : a)
template<class T> void cout_1d(T &v) { FORA(i, v) cout << i << " "; puts(""); }
template<class T> void cout_2d(T &vv) { FORA(v, vv) cout_1d(v); }
#define ALL(X) (X).begin(), (X).end()
#define RALL(X) (X).rbegin(), (X).rend()
#define SIZE(X) ((int)(X).size())
#define UNIQUE(x) (X).erase(unique(ALL(x), (X).end())
#define ZERO(a) memset(a, 0, sizeof(a))
#define NEG1(a) memset(a, -1, sizeof(a))
#define MAXA(a) memset(a, 0x3f, sizeof(a))
#define MAXB(b) memset(b, 0x7f, sizeof(b))
#define MP make_pair
#define PB push_back
#define X first
#define Y second

const LD PI = acos(-1.0);
const LL MOD = 998244353;
//const LL MOD = 1e9+7;
const LL MAXN = 2e5 + 7;

int h[MAXN];
void solve1() {
	int N;  IN(N);
	REPN(i, N) IN(h[i]);
	// VI dp(N+1, 0);  dp[2] = abs(h[2] - h[1]);
	// REP(i, 3, N) dp[i] = min(dp[i-1] + abs(h[i] - h[i-1]), dp[i-2] + abs(h[i] - h[i-2]));
	VI dp(N+1, 0);
	REP(i, 2, N) dp[i] = min(dp[i-1] + abs(h[i] - h[i-1]), 
			i <= 2 ? INT_MAX : dp[i-2] + abs(h[i] - h[i-2]));
	cout << dp[N] << endl;
}

void solve2() {
	int N, K;  IN(N, K);
	REPN(i, N) IN(h[i]);
	VI dp(N+1, INT_MAX);
	dp[1] = 0;
	REP(i, 2, N) REP(j, 1, K) // if (j >= i) break;
		dp[i] = min(dp[i], i <= j ? INT_MAX : dp[i-j] + abs(h[i] - h[i-j]));
	cout << dp[N] << endl;
}

// int a[MAXN], b[MAXN], c[MAXN];
int v3[MAXN][3];
void solve_Vacation() {
	// int N;  IN(N);
	// int mxa, mxb, mxc;
	// REPN(i, N) IN(a[i], b[i], c[i]);
	// mxa = a[1];  mxb = b[1];  mxc = c[1];
	// REP(i, 2, N) {
	//     int ta = mxa, tb = mxb, tc = mxc;
	//     mxa = a[i] + max(tb, tc);
	//     mxb = b[i] + max(ta, tc);
	//     mxc = c[i] + max(ta, tb);
	// }
	// cout << max(mxa, max(mxb, mxc)) << endl;
	int N;  IN(N);
	FORN(i, N) FORN(j, 3) IN(v3[i][j]);
	VI mx(v3[0], v3[0]+3);
	FOR(i, 1, N) {
		VI t = mx;
		FORN(j, 3)
			mx[j] = v3[i][j] + max(t[(j+1)%3], t[(j+2)%3]);
	}
	cout << *max_element(ALL(mx)) << endl;
}

LL w[MAXN], v[MAXN];
void solve_Knapsack_1() {
	// N -- 100, W -- 1e5, vi -- 1e9
	int N, W;  IN(N, W);
	REPN(i, N) IN(w[i], v[i]);
	VV<LL> dp(N+1, V<LL>(W+1, 0));		// dp[i][j] -- 从 前i个 物品 挑选总重量 <= j 的 最大总价值, dp[0][j] = 0
	REPN(i, N) REP(j, 0, W)
		dp[i][j] = (j < w[i]) ? dp[i-1][j] : max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]);
	cout << dp[N][W] << endl;
}
void solve_Knapsack_2() {
	// N -- 100, W -- 1e9, vi -- 1e3
	int N, W;  IN(N, W);
	REPN(i, N) IN(w[i], v[i]);
	VV<LL> dp(100+7, V<LL>(1e3*1e2+7, INT_MAX));	// dp[i][j] -- 从 前i个 物品 挑选总价值=j 的 最小总重量, dp[0][0] = 0, dp[0][j]=INF;
	dp[0][0] = 0;
	REPN(i, N) REP(j, 0, 1e3*1e2)
		dp[i][j] = (j < v[i]) ? dp[i-1][j] : min(dp[i-1][j], dp[i-1][j-v[i]] + w[i]);
	PER(j, 1e3*1e2, 0) if (dp[N][j] <= W) { cout << j << endl; return; }
}

void solve_LCS() {
	string s, t;  cin >> s >> t;
	VVI dp(s.size()+1, VI(t.size()+1, 0));
	VVI flag(s.size()+1, VI(t.size()+1, 0));
	REPN(i, s.size()) REPN(j, t.size())
		if (s[i-1] == t[j-1]) {
			dp[i][j] = dp[i-1][j-1]+1;
			flag[i][j] = 0;
		} else {
			dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
			flag[i][j] = (dp[i][j-1] > dp[i-1][j]) ? 1 : 2;
		}
		// dp[i][j] = (s[i] == t[j]) ? dp[i-1][j-1]+1 : max(dp[i][j-1], dp[i-1][j]);
	// cout << dp[s.size()][t.size()] << endl;
	string res = "";
	int x = s.size(), y = t.size();
	while (x >= 1 && y >= 1) {
		if (flag[x][y] == 0) {
			res = s[x-1] + res;
			--x;  --y;
		} else if (flag[x][y] == 1)
			--y;
		else if (flag[x][y] == 2)
			--x;
	}
	cout << res << endl;
}

int x[MAXN], y[MAXN];
VI adj[MAXN];
void dfs_LP(VI &dp, VI &vis, int u) {
	vis[u] = 1;
	FORA(v, adj[u]) {
		if (!vis[v]) dfs_LP(dp, vis, v);
		dp[u] = max(dp[u], dp[v]+1);
	}
}
void solve_LP() {
	int N, M;  IN(N, M);
	REPN(i, M) {
		int x, y;  IN(x, y);
		adj[x].PB(y);
	}
	VI dp(N+1, 0), vis(N+1, 0);
	REPN(i, N) if (!vis[i]) dfs_LP(dp, vis, i);
	cout << *max_element(dp.begin()+1, dp.end()) << endl;
}

int main() {
#ifdef _DEBUG
    freopen("../in.txt", "r", stdin);
    freopen("../out.txt", "w", stdout);
#endif
    // FastI

	// solve1();
	// solve2();
	//
	// solve_Vacation();
	//
	// solve_Knapsack_1();
	// solve_Knapsack_2();

	// solve_LCS();
	solve_LP();
    return 0;
}


Measured memory_bytes: 12288